relaton-render 3.0.0.pre.alpha.21 → 3.0.0.pre.alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/relaton/render/general.rb +26 -10
- data/lib/relaton/render/iso690/element.rb +5 -2
- data/lib/relaton/render/iso690/elements/creator.rb +22 -3
- data/lib/relaton/render/iso690/elements/edition.rb +30 -1
- data/lib/relaton/render/iso690/elements/extent.rb +22 -5
- data/lib/relaton/render/iso690/elements/production.rb +12 -4
- data/lib/relaton/render/iso690/elements/series.rb +5 -1
- data/lib/relaton/render/iso690/elements/size.rb +5 -1
- data/lib/relaton/render/iso690/fields.rb +15 -0
- data/lib/relaton/render/iso690/i18n/en.yml +15 -4
- data/lib/relaton/render/iso690/i18n/ja.yml +38 -0
- data/lib/relaton/render/iso690/i18n.rb +1 -0
- data/lib/relaton/render/iso690/renderer.rb +28 -1
- data/lib/relaton/render/iso690/style/scheme.rb +7 -1
- data/lib/relaton/render/iso690/style.rb +11 -0
- data/lib/relaton/render/iso690/template.rb +83 -8
- data/lib/relaton/render/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84f33badbec6cb9d4d80c763d0538b9a3bde40dea703623568cb52a4758134bf
|
|
4
|
+
data.tar.gz: b6d9d4b6317b917472350aa45c7c7056b4eb8f68337daea43a97a3603cbf8517
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dd0961f370beaf6e0bc3b5233d71aee7d47773b4443a956de18278228356f164f90c6e62a9da2bb19019f1cd4076675fdc85fa9e56b1f47395d0d134912540dc
|
|
7
|
+
data.tar.gz: 4331fc6e0974c1975b8340e374f23522f7d252aa6dfb3b65d37afa8da919128c78f5b7589115c06c25cf74dfac0649546177b4f8494dd969cb6291e486f8401c
|
|
@@ -79,13 +79,15 @@ module Relaton
|
|
|
79
79
|
next
|
|
80
80
|
end
|
|
81
81
|
m[item.id] = {
|
|
82
|
-
id: item.id, ord: i,
|
|
83
82
|
author: renderer.in_text_author(item),
|
|
84
|
-
|
|
83
|
+
date: renderer.disambiguated_date(item,
|
|
84
|
+
disambiguator:
|
|
85
|
+
disambiguators[item.id]),
|
|
85
86
|
citation: citation_renderings(item, ref, renderer,
|
|
86
87
|
type: type,
|
|
87
88
|
disambiguator:
|
|
88
89
|
disambiguators[item.id]),
|
|
90
|
+
formattedref: terminate_reference(ref, item),
|
|
89
91
|
}
|
|
90
92
|
end
|
|
91
93
|
end
|
|
@@ -93,7 +95,7 @@ module Relaton
|
|
|
93
95
|
# isodoc's styled citations consume these keys: the default is the
|
|
94
96
|
# authoritative identifier; the short cite is the style's citation,
|
|
95
97
|
# falling back to the reference rendering (the 1.x short-cite)
|
|
96
|
-
FIRST_DELIM =
|
|
98
|
+
FIRST_DELIM = '<span class="fmt-first-biblio-delim"/>'
|
|
97
99
|
|
|
98
100
|
# A creator list alone (flavors' document-history name forms)
|
|
99
101
|
def creator_names(item)
|
|
@@ -141,22 +143,33 @@ module Relaton
|
|
|
141
143
|
# names the key)
|
|
142
144
|
def citation_renderings(item, ref, renderer, type: "author-date",
|
|
143
145
|
disambiguator: nil)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
# A style declaring shortFromReference takes the reference form
|
|
147
|
+
# with the first-biblio marker (the 1.x citetemplate short)
|
|
148
|
+
short = if renderer.short_from_reference?
|
|
146
149
|
renderer.render_short(item, FIRST_DELIM)
|
|
147
150
|
else
|
|
148
|
-
short
|
|
151
|
+
short = renderer.citation(item)
|
|
152
|
+
short.empty? ? renderer.render_short(item, FIRST_DELIM) :
|
|
153
|
+
short
|
|
149
154
|
end
|
|
150
155
|
|
|
156
|
+
title = renderer.title_citation(item)
|
|
157
|
+
|
|
151
158
|
{
|
|
152
159
|
full: ref,
|
|
153
160
|
default: item.docidentifier.first&.content.to_s,
|
|
154
161
|
short: short,
|
|
155
|
-
author_date: renderer.
|
|
162
|
+
author_date: renderer.citation(item,
|
|
163
|
+
disambiguator: disambiguator),
|
|
164
|
+
author_date_br: renderer.bracketed_date_citation(
|
|
156
165
|
item, disambiguator: disambiguator,
|
|
157
166
|
),
|
|
158
167
|
author: renderer.in_text_author(item),
|
|
159
|
-
|
|
168
|
+
date: renderer.disambiguated_date(item),
|
|
169
|
+
# reference_tag: no rendering — isodoc falls back to the
|
|
170
|
+
# biblio-tag anchor (the 1.x nil)
|
|
171
|
+
title: title,
|
|
172
|
+
title_reference_tag: title,
|
|
160
173
|
}
|
|
161
174
|
end
|
|
162
175
|
|
|
@@ -232,7 +245,9 @@ module Relaton
|
|
|
232
245
|
end
|
|
233
246
|
out.empty? or break
|
|
234
247
|
end
|
|
235
|
-
|
|
248
|
+
# esc-wrapped: isodoc's l10n skips the tags, leaving a standard
|
|
249
|
+
# identifier's punctuation verbatim (the 1.x Parse behaviour)
|
|
250
|
+
out.map { |x| "<esc>#{x.text.strip}</esc>" }
|
|
236
251
|
end
|
|
237
252
|
|
|
238
253
|
def facade_id_type(id)
|
|
@@ -256,7 +271,8 @@ module Relaton
|
|
|
256
271
|
# and every flavor still pass string keys.
|
|
257
272
|
def deep_symbolize(value)
|
|
258
273
|
case value
|
|
259
|
-
|
|
274
|
+
# isodoc i18n hashes carry nil keys (an unlabeled punct slot)
|
|
275
|
+
when Hash then value.to_h { |k, v| [k&.to_sym, deep_symbolize(v)] }
|
|
260
276
|
when Array then value.map { |v| deep_symbolize(v) }
|
|
261
277
|
else value
|
|
262
278
|
end
|
|
@@ -118,9 +118,12 @@ module Relaton
|
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
def join_names(names)
|
|
121
|
-
# A style with no join word renders a plain serial list
|
|
121
|
+
# A style with no join word renders a plain serial list,
|
|
122
|
+
# separated per the locale (the comma, or the CJK 、)
|
|
122
123
|
if @i18n.label("and").empty? && names.size > 1
|
|
123
|
-
|
|
124
|
+
sep = @i18n.label("list_separator")
|
|
125
|
+
sep = ", " if sep == "list_separator"
|
|
126
|
+
return names.join(sep)
|
|
124
127
|
end
|
|
125
128
|
|
|
126
129
|
oxford = @i18n.label("oxford_comma")
|
|
@@ -34,12 +34,12 @@ module Relaton
|
|
|
34
34
|
# from the next element, which follows directly in the
|
|
35
35
|
# template; a lone editor is unmarked unless declared
|
|
36
36
|
if editors? && marked?
|
|
37
|
-
"#{period(joined)}
|
|
37
|
+
"#{period(joined)}#{role_space}#{role_parenthesis} "
|
|
38
38
|
else
|
|
39
39
|
"#{period(joined)} "
|
|
40
40
|
end
|
|
41
41
|
else
|
|
42
|
-
marker = editors? && marked? ? "
|
|
42
|
+
marker = editors? && marked? ? "#{role_space}#{role_parenthesis}" : ''
|
|
43
43
|
"#{joined}#{marker}"
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -48,10 +48,29 @@ module Relaton
|
|
|
48
48
|
# plain join, without the wrap and sentence period (1.x
|
|
49
49
|
# short-cite templates carried no wrap)
|
|
50
50
|
def plain_render
|
|
51
|
-
marker = editors? &&
|
|
51
|
+
marker = editors? && marked? ? "#{role_space}#{role_parenthesis}" : ''
|
|
52
52
|
"#{join(names)}#{marker}"
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# The editor role marker's parentheses follow the locale
|
|
56
|
+
# (ASCII for Latin scripts, fullwidth for CJK)
|
|
57
|
+
def role_parenthesis
|
|
58
|
+
open = @i18n.punct_fetch("open-paren", "(")
|
|
59
|
+
close = @i18n.punct_fetch("close-paren", ")")
|
|
60
|
+
"#{open}#{role_word}#{close}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# CJK cites the role marker tight against the name list
|
|
64
|
+
def role_space
|
|
65
|
+
@i18n.punct_fetch("marker-space", " ")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# The template-level role slot ("{{role}}"): the marker with
|
|
69
|
+
# its locale spacing, when the creators are all editors
|
|
70
|
+
def role_marker
|
|
71
|
+
editors? ? "#{role_space}#{role_parenthesis}" : ""
|
|
72
|
+
end
|
|
73
|
+
|
|
55
74
|
def role_placement
|
|
56
75
|
@style.scheme.name_form.role_placement || "glue"
|
|
57
76
|
end
|
|
@@ -14,10 +14,39 @@ module Relaton
|
|
|
14
14
|
def render
|
|
15
15
|
return "#{@i18n.label('version')} #{raw}" unless word_edition?
|
|
16
16
|
|
|
17
|
+
# The worded forms first ("First edition", "第N版" via the
|
|
18
|
+
# ordinal template), the cardinal last
|
|
19
|
+
ordinal = locale_template("edition_ordinal", number)
|
|
20
|
+
return ordinal if ordinal
|
|
21
|
+
|
|
17
22
|
word = @i18n.label("edition_#{number}")
|
|
18
23
|
return word unless word == "edition_#{number}"
|
|
19
24
|
|
|
20
|
-
"#{ordinalize(number)} #{@i18n.label('edition')}"
|
|
25
|
+
cardinal_form || "#{ordinalize(number)} #{@i18n.label('edition')}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The plain cardinal form ("edition 7")
|
|
29
|
+
def cardinal_form
|
|
30
|
+
locale_template("edition_cardinal", number) ||
|
|
31
|
+
locale_template("version_cardinal", number)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# A locale template carrying {{ var1 }} (optionally through
|
|
37
|
+
# the ordinal_word filter) populated with the edition number;
|
|
38
|
+
# a bare label (no placeholder) is not one
|
|
39
|
+
def locale_template(key, value)
|
|
40
|
+
raw = @i18n.label(key)
|
|
41
|
+
return nil if raw == key || raw !~ /\{{/
|
|
42
|
+
|
|
43
|
+
if raw.include?("ordinal_word")
|
|
44
|
+
word = @i18n.label("ordinal_word_#{value}")
|
|
45
|
+
word = ordinalize(value) if word == "ordinal_word_#{value}"
|
|
46
|
+
raw.gsub(/\{\{\s*var1[^}]*\}\}/, word)
|
|
47
|
+
else
|
|
48
|
+
raw.gsub("{{ var1 }}", value.to_s)
|
|
49
|
+
end
|
|
21
50
|
end
|
|
22
51
|
|
|
23
52
|
private
|
|
@@ -12,17 +12,34 @@ module Relaton
|
|
|
12
12
|
|
|
13
13
|
def render
|
|
14
14
|
groups = [numeration, page_range].reject { |g| g.empty? }
|
|
15
|
-
groups.join(
|
|
15
|
+
groups.join(group_sep)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
private
|
|
19
19
|
|
|
20
|
+
# An extent label is a template over its value: "vol. %" in
|
|
21
|
+
# the Latin pack, "巻%" / "%頁" in the CJK packs
|
|
22
|
+
def unit(type, value)
|
|
23
|
+
label = @i18n.label(type)
|
|
24
|
+
return "#{label} #{value}" unless label.include?("%")
|
|
25
|
+
|
|
26
|
+
label.sub("%", value)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def cjk?(label)
|
|
30
|
+
label.match?(/\p{Han}|\p{Hiragana}|\p{Katakana}/)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def group_sep
|
|
34
|
+
cjk?(@i18n.label("page")) ? "、 " : ", "
|
|
35
|
+
end
|
|
36
|
+
|
|
20
37
|
def numeration
|
|
21
38
|
%w[volume issue].filter_map do |type|
|
|
22
39
|
loc = localities.find { |l| l.type == type }
|
|
23
40
|
next if loc.nil? || loc.reference_from.to_s.empty?
|
|
24
41
|
|
|
25
|
-
|
|
42
|
+
unit(type, loc.reference_from)
|
|
26
43
|
end.join(" ")
|
|
27
44
|
end
|
|
28
45
|
|
|
@@ -31,10 +48,10 @@ module Relaton
|
|
|
31
48
|
from = loc.reference_from.to_s
|
|
32
49
|
to = loc.reference_to.to_s
|
|
33
50
|
if to.empty? || to == from
|
|
34
|
-
"
|
|
51
|
+
unit("page", from)
|
|
35
52
|
else
|
|
36
|
-
"#{@i18n.label('
|
|
37
|
-
|
|
53
|
+
range = "#{from}#{@i18n.label('date_range')}#{to}"
|
|
54
|
+
unit("pages", range)
|
|
38
55
|
end
|
|
39
56
|
end
|
|
40
57
|
|
|
@@ -17,17 +17,24 @@ module Relaton
|
|
|
17
17
|
return no_place_production_publisher_first if places.empty? &&
|
|
18
18
|
no_place_declared?
|
|
19
19
|
|
|
20
|
-
return [publishers.join("; "), places.
|
|
20
|
+
return [publishers.join("; "), places.map { |p| cjk_place(p) }]
|
|
21
21
|
.reject(&:empty?).join(production_sep)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
return no_place_production if places.empty? && no_place_declared?
|
|
25
25
|
|
|
26
|
-
[places.
|
|
26
|
+
[places.map { |p| cjk_place(p) }, publishers.join("; ")]
|
|
27
27
|
.reject(&:empty?).join(production_sep)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
# A CJK locale's place names carry the CJK-Latin separator
|
|
31
|
+
# ("Cambridge、UK" over "Cambridge, UK")
|
|
32
|
+
def cjk_place(place)
|
|
33
|
+
sep = @i18n.punct_fetch("cjk-latin-separator", "")
|
|
34
|
+
sep.empty? ? place : place.gsub(", ", sep)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def publisher_first?
|
|
31
38
|
@i18n.punct_fetch("production_order", "") == "publisher_first"
|
|
32
39
|
end
|
|
33
40
|
|
|
@@ -50,7 +57,8 @@ module Relaton
|
|
|
50
57
|
return "" if label.empty? || label == "no_place"
|
|
51
58
|
|
|
52
59
|
pubs = publishers.join("; ")
|
|
53
|
-
pubs.empty? ? "#{label}
|
|
60
|
+
pubs.empty? ? "#{label}#{production_sep}".rstrip :
|
|
61
|
+
"#{label}#{production_sep}#{pubs}"
|
|
54
62
|
end
|
|
55
63
|
|
|
56
64
|
def no_place_declared?
|
|
@@ -25,7 +25,11 @@ module Relaton
|
|
|
25
25
|
if number.empty?
|
|
26
26
|
base
|
|
27
27
|
else
|
|
28
|
-
|
|
28
|
+
# an empty series_no label joins on the space alone (the
|
|
29
|
+
# CJK form: "Series 472")
|
|
30
|
+
label = @i18n.label("series_no")
|
|
31
|
+
label.empty? ? "#{base} #{number}" :
|
|
32
|
+
"#{base}, #{label} #{number}"
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
|
|
@@ -28,7 +28,11 @@ module Relaton
|
|
|
28
28
|
|
|
29
29
|
type = value.is_a?(Hash) ? value[:type] : value.type
|
|
30
30
|
unit = type && @i18n.label("size_#{type}")
|
|
31
|
-
unit.nil? || unit == "size_#{type}"
|
|
31
|
+
return content if unit.nil? || unit == "size_#{type}"
|
|
32
|
+
|
|
33
|
+
# The value/unit glue is locale-declared (CJK cites tight,
|
|
34
|
+
# "巻1" over "vol. 1")
|
|
35
|
+
"#{unit}#{@i18n.punct_fetch('size-join', ' ')}#{content}"
|
|
32
36
|
end
|
|
33
37
|
end
|
|
34
38
|
end
|
|
@@ -30,6 +30,7 @@ module Relaton
|
|
|
30
30
|
key = slot.to_s.delete("_").downcase
|
|
31
31
|
table[key] = element_field(slot)
|
|
32
32
|
end
|
|
33
|
+
table["role"] = role_field
|
|
33
34
|
table["dategroup"] = dategroup_field
|
|
34
35
|
table["disambiguateddate"] = disambiguated_date_field(table["date"])
|
|
35
36
|
unless table["dategroup"].present?
|
|
@@ -38,6 +39,20 @@ module Relaton
|
|
|
38
39
|
table.merge(name_fields)
|
|
39
40
|
end
|
|
40
41
|
|
|
42
|
+
# The creators' editor-role marker ("(eds.)", "(編)"), as a
|
|
43
|
+
# template slot: a creator list that is not all editors cites no
|
|
44
|
+
# role
|
|
45
|
+
def role_field
|
|
46
|
+
creator = Elements.build(:creator, @model, style: @style,
|
|
47
|
+
i18n: @i18n, elements: @elements)
|
|
48
|
+
return Template::Field[false, ""] unless
|
|
49
|
+
creator&.present? && creator.respond_to?(:role_marker)
|
|
50
|
+
|
|
51
|
+
marker = creator.role_marker
|
|
52
|
+
marker.empty? ? Template::Field[false, ""] :
|
|
53
|
+
Template::Field[true, marker]
|
|
54
|
+
end
|
|
55
|
+
|
|
41
56
|
# The date carrying the batch disambiguation suffix ("2022a"):
|
|
42
57
|
# identity when the caller passes none
|
|
43
58
|
def disambiguated_date_field(date)
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
lang: en
|
|
2
2
|
labels:
|
|
3
3
|
edition: "ed"
|
|
4
|
+
ordinal_word_1: "First"
|
|
5
|
+
ordinal_word_2: "Second"
|
|
6
|
+
ordinal_word_3: "Third"
|
|
7
|
+
ordinal_word_4: "Fourth"
|
|
8
|
+
ordinal_word_5: "Fifth"
|
|
9
|
+
ordinal_word_6: "Sixth"
|
|
10
|
+
ordinal_word_7: "Seventh"
|
|
11
|
+
ordinal_word_8: "Eighth"
|
|
12
|
+
ordinal_word_9: "Ninth"
|
|
13
|
+
ordinal_word_10: "Tenth"
|
|
4
14
|
size_volume: "vol."
|
|
5
15
|
size_page: "pp."
|
|
6
|
-
page: "p."
|
|
7
|
-
pages: "pp."
|
|
8
|
-
volume: "vol."
|
|
9
|
-
issue: "no."
|
|
16
|
+
page: "p. %"
|
|
17
|
+
pages: "pp. %"
|
|
18
|
+
volume: "vol. %"
|
|
19
|
+
issue: "no. %"
|
|
20
|
+
no_place: "n.p."
|
|
10
21
|
version: "Version"
|
|
11
22
|
medium_website: "[website]"
|
|
12
23
|
viewed: "viewed"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
lang: ja
|
|
2
|
+
labels:
|
|
3
|
+
edition: "版"
|
|
4
|
+
size_volume: "巻"
|
|
5
|
+
size_page: "頁"
|
|
6
|
+
page: "%頁"
|
|
7
|
+
pages: "%頁"
|
|
8
|
+
volume: "巻%"
|
|
9
|
+
issue: "%号"
|
|
10
|
+
version: "版"
|
|
11
|
+
viewed: "閲覧"
|
|
12
|
+
series_no: "番号"
|
|
13
|
+
report_no: "報告番号"
|
|
14
|
+
available_from: "入手先:"
|
|
15
|
+
at_url: "URL:"
|
|
16
|
+
in: "収録:"
|
|
17
|
+
ed: "編"
|
|
18
|
+
eds: "編"
|
|
19
|
+
updated: "更新"
|
|
20
|
+
no_place: "出版地不明"
|
|
21
|
+
edition_cardinal: "第{{ var1 }}版"
|
|
22
|
+
edition_ordinal: "第{{ var1 }}版"
|
|
23
|
+
version_cardinal: "第{{ var1 }}版"
|
|
24
|
+
in_series: "シリーズ"
|
|
25
|
+
list_separator: "、 "
|
|
26
|
+
and: ""
|
|
27
|
+
oxford_comma: ""
|
|
28
|
+
date_range: "〜"
|
|
29
|
+
punct:
|
|
30
|
+
size-join: ""
|
|
31
|
+
marker-space: ""
|
|
32
|
+
production_sep: ": "
|
|
33
|
+
cjk-latin-separator: "、 "
|
|
34
|
+
period: "。"
|
|
35
|
+
comma: "、"
|
|
36
|
+
colon: ":"
|
|
37
|
+
open-paren: "("
|
|
38
|
+
close-paren: ")"
|
|
@@ -43,6 +43,7 @@ module Relaton
|
|
|
43
43
|
known = %w[
|
|
44
44
|
edition series_no report_no available_from in and oxford_comma
|
|
45
45
|
ed eds date_range others no_date no_author at
|
|
46
|
+
edition_ordinal edition_cardinal version_cardinal
|
|
46
47
|
]
|
|
47
48
|
hash.each do |key, value|
|
|
48
49
|
labels[key.to_s] = value if known.include?(key.to_s) && !value.nil?
|
|
@@ -64,7 +64,8 @@ module Relaton
|
|
|
64
64
|
# The short cite: the reference with the first-biblio marker
|
|
65
65
|
def render_short(model, delim)
|
|
66
66
|
kind = @style.kind_for(model.type)
|
|
67
|
-
template = @style.
|
|
67
|
+
template = @style.short_template_for(kind,
|
|
68
|
+
home: home_docid?(model)) ||
|
|
68
69
|
@style.template_for(kind, home: home_docid?(model))
|
|
69
70
|
Template.new(template).evaluate_short(
|
|
70
71
|
Fields.new(model, style: @style, i18n: @i18n, short: true,
|
|
@@ -92,6 +93,32 @@ module Relaton
|
|
|
92
93
|
.reject(&:empty?).join(" ")
|
|
93
94
|
end
|
|
94
95
|
|
|
96
|
+
# The bracketed author-date in-text capsule ("Aluffi (2022)"):
|
|
97
|
+
# the author and the PLAIN date (un-disambiguated, the 1.x
|
|
98
|
+
# citetemplate's {{ date }}) in the locale's parentheses
|
|
99
|
+
def bracketed_date_citation(model, **)
|
|
100
|
+
f = Fields.new(model, style: @style, i18n: @i18n,
|
|
101
|
+
elements: @elements).to_h
|
|
102
|
+
date = f["date"].text
|
|
103
|
+
return "" if date.empty?
|
|
104
|
+
|
|
105
|
+
open = @i18n.punct_fetch("open-paren", "(")
|
|
106
|
+
close = @i18n.punct_fetch("close-paren", ")")
|
|
107
|
+
[in_text_author(model), "#{open}#{date}#{close}"]
|
|
108
|
+
.reject(&:empty?).join(" ")
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# The disambiguated date alone (the citation renderings' date)
|
|
112
|
+
def disambiguated_date(model, disambiguator: nil)
|
|
113
|
+
Fields.new(model, style: @style, i18n: @i18n,
|
|
114
|
+
disambiguator: disambiguator,
|
|
115
|
+
elements: @elements).to_h["disambiguateddate"].text
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def short_from_reference?
|
|
119
|
+
@style.scheme.short_from_reference
|
|
120
|
+
end
|
|
121
|
+
|
|
95
122
|
# The title citation ("{{ title }}" in the 1.x citetemplate):
|
|
96
123
|
# the title element's plain form, no style markers
|
|
97
124
|
def title_citation(model)
|
|
@@ -13,12 +13,18 @@ module Relaton
|
|
|
13
13
|
attribute :home_docid_type, :string, collection: true
|
|
14
14
|
attribute :default_kind, :string, default: ""
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
# The renderings' short cite takes the reference form with the
|
|
17
|
+
# first-biblio marker (the 1.x citetemplate short), not the
|
|
18
|
+
# citation template
|
|
19
|
+
attribute :short_from_reference, :boolean, default: -> { false }
|
|
20
|
+
|
|
21
|
+
key_value do
|
|
17
22
|
map "system", to: :system
|
|
18
23
|
map "nameForm", to: :name_form
|
|
19
24
|
map "locale", to: :locale
|
|
20
25
|
map "homeDocidType", to: :home_docid_type
|
|
21
26
|
map "defaultKind", to: :default_kind
|
|
27
|
+
map "shortFromReference", to: :short_from_reference
|
|
22
28
|
end
|
|
23
29
|
end
|
|
24
30
|
end
|
|
@@ -66,6 +66,17 @@ module Relaton
|
|
|
66
66
|
per_type.find { |t| t.type == type.to_s }
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# The home split applies to the short cite as it does to the
|
|
70
|
+
# reference template (a home standard's short cite is not an
|
|
71
|
+
# external standard's)
|
|
72
|
+
def short_template_for(type, home: nil)
|
|
73
|
+
candidates = per_type.select { |t| t.type == type.to_s }
|
|
74
|
+
if candidates.size > 1 && !home.nil?
|
|
75
|
+
candidates = candidates.select { |t| (t.home || false) == home }
|
|
76
|
+
end
|
|
77
|
+
candidates.filter_map(&:short).first
|
|
78
|
+
end
|
|
79
|
+
|
|
69
80
|
# The absent-slot replacement text declared for a type, when any
|
|
70
81
|
def fallback_for(type, slot)
|
|
71
82
|
type_template_for(type)&.fallbacks&.[](slot.to_s)
|
|
@@ -30,8 +30,18 @@ module Relaton
|
|
|
30
30
|
present = present_indices(fields)
|
|
31
31
|
return "" if present.empty?
|
|
32
32
|
|
|
33
|
+
# The split marker follows the leading run of present slots
|
|
34
|
+
# (the 1.x first SEGMENT: "{{creator}}{{role}}" splits after
|
|
35
|
+
# the role), before the first literal that follows it
|
|
36
|
+
lead_slots = []
|
|
37
|
+
@chunks.each_with_index do |(kind, _value), i|
|
|
38
|
+
break if kind != :slot || !present.include?(i)
|
|
39
|
+
|
|
40
|
+
lead_slots << i
|
|
41
|
+
end
|
|
42
|
+
split_at = lead_slots.last ? lead_slots.last + 1 : nil
|
|
43
|
+
|
|
33
44
|
out = +""
|
|
34
|
-
first_seen = false
|
|
35
45
|
@chunks.each_with_index do |(kind, value), i|
|
|
36
46
|
text =
|
|
37
47
|
case kind
|
|
@@ -39,18 +49,20 @@ module Relaton
|
|
|
39
49
|
field = fields[normalise(value)]
|
|
40
50
|
next unless field&.present?
|
|
41
51
|
|
|
42
|
-
|
|
52
|
+
field.text
|
|
43
53
|
else
|
|
44
|
-
# the split marker precedes the component's trailing
|
|
45
|
-
# punctuation (1.x ret[0] += delim, then join), with
|
|
46
|
-
# the join's separating space
|
|
47
54
|
next unless bridged?(i, present)
|
|
48
55
|
|
|
49
56
|
value
|
|
50
57
|
end
|
|
51
|
-
|
|
58
|
+
if split_at == i
|
|
59
|
+
out << fieldless(lead_slots, fields) if false
|
|
60
|
+
out << delim.to_s
|
|
61
|
+
split_at = nil
|
|
62
|
+
end
|
|
52
63
|
out << text unless text.nil?
|
|
53
64
|
end
|
|
65
|
+
out << delim.to_s if split_at == @chunks.length
|
|
54
66
|
terminate(out).rstrip
|
|
55
67
|
end
|
|
56
68
|
|
|
@@ -64,10 +76,44 @@ module Relaton
|
|
|
64
76
|
return "" if present.empty?
|
|
65
77
|
|
|
66
78
|
out = +"".dup
|
|
79
|
+
# Parenthetical groups balance on the template's literal
|
|
80
|
+
# parens alone: data text (a series run "(N.S.)", a host
|
|
81
|
+
# creator's closing paren) carries parens of its own that
|
|
82
|
+
# are no part of the template's group structure
|
|
83
|
+
paren_balance = 0
|
|
67
84
|
@chunks.each_with_index do |(kind, value), i|
|
|
68
85
|
if kind == :slot
|
|
69
86
|
field = fields[normalise(value)]
|
|
70
87
|
out << field.text if field&.present?
|
|
88
|
+
elsif value.to_s.match?(/\A[))]/)
|
|
89
|
+
# Symmetric close: with no pending open the close-paren
|
|
90
|
+
# drops, and any trailing punctuation bridges normally
|
|
91
|
+
closes = value.to_s[/\A[))]+/]
|
|
92
|
+
emitted = [paren_balance, closes.size].min
|
|
93
|
+
if emitted.positive?
|
|
94
|
+
out << closes[0, emitted] +
|
|
95
|
+
value.to_s[closes.size..].to_s
|
|
96
|
+
paren_balance -= emitted
|
|
97
|
+
else
|
|
98
|
+
rest = value.to_s.sub(/\A[))]+/, "")
|
|
99
|
+
# the trailing separator of a dropped group bridges as
|
|
100
|
+
# though the group were never there
|
|
101
|
+
if !rest.empty? && present.any? { |j| j > i } &&
|
|
102
|
+
group_gap?(i, present)
|
|
103
|
+
out << rest
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
elsif value.to_s.match?(/[((]\z/)
|
|
107
|
+
# A literal opening a parenthetical group ("({{series}})",
|
|
108
|
+
# "。({{series}})") attaches its paren to the slot it
|
|
109
|
+
# opens — the pair drops with an absent element, while
|
|
110
|
+
# any leading punctuation bridges normally
|
|
111
|
+
lead, paren = value.to_s.match(/\A(.*)([((])\z/).captures
|
|
112
|
+
out << lead if bridged_text?(i, lead, present)
|
|
113
|
+
if present.include?(i + 1)
|
|
114
|
+
out << paren
|
|
115
|
+
paren_balance += 1
|
|
116
|
+
end
|
|
71
117
|
elsif bridged?(i, present) ||
|
|
72
118
|
(value.include?("<") && present.any? { |j| j < i })
|
|
73
119
|
# markup attaches to the element it closes
|
|
@@ -102,6 +148,30 @@ module Relaton
|
|
|
102
148
|
end
|
|
103
149
|
end
|
|
104
150
|
|
|
151
|
+
# The texts between this close and the last present slot are
|
|
152
|
+
# all parenthetical-group parts (each dropped or partial)
|
|
153
|
+
def group_gap?(index, present)
|
|
154
|
+
left = present.select { |i| i < index }.max
|
|
155
|
+
@chunks[(left + 1)...index].all? do |(_, text)|
|
|
156
|
+
text.to_s.match?(/\A[))]|[((]\z/)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# The leading punctuation of a paren-opening literal bridges
|
|
161
|
+
# per the segment-join rule (a bare paren has no lead)
|
|
162
|
+
def bridged_text?(index, lead, present)
|
|
163
|
+
return true if lead.empty?
|
|
164
|
+
|
|
165
|
+
first_slot = @chunks.index { |(kind, _)| kind == :slot }
|
|
166
|
+
return present.include?(first_slot) if index < first_slot
|
|
167
|
+
|
|
168
|
+
left = present.select { |i| i < index }.max
|
|
169
|
+
left && present.any? { |i| i > index } &&
|
|
170
|
+
!@chunks[(left + 1)...index].any? do |(kind, _)|
|
|
171
|
+
kind == :text
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
105
175
|
# A literal is the trailing separator of the element that
|
|
106
176
|
# precedes it: it renders when that element renders and a
|
|
107
177
|
# later element renders, and it is the FIRST literal of its
|
|
@@ -124,9 +194,14 @@ module Relaton
|
|
|
124
194
|
end
|
|
125
195
|
|
|
126
196
|
# A template's paired literal ("({{production}})") closes even
|
|
127
|
-
# when nothing follows the present element it wraps
|
|
197
|
+
# when nothing follows the present element it wraps. Fullwidth
|
|
198
|
+
# parens (CJK) pair the same way
|
|
128
199
|
def close_pending_paren?(out, value)
|
|
129
|
-
value.start_with?(")"
|
|
200
|
+
return false unless value.start_with?(")", "\uFF09")
|
|
201
|
+
|
|
202
|
+
opens = out.count("(") + out.count("\uFF08")
|
|
203
|
+
closes = out.count(")") + out.count("\uFF09")
|
|
204
|
+
opens > closes
|
|
130
205
|
end
|
|
131
206
|
|
|
132
207
|
def terminate(body)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: relaton-render
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.0.pre.alpha.
|
|
4
|
+
version: 3.0.0.pre.alpha.23
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: htmlentities
|
|
@@ -143,6 +143,7 @@ files:
|
|
|
143
143
|
- lib/relaton/render/iso690/i18n.rb
|
|
144
144
|
- lib/relaton/render/iso690/i18n/en.yml
|
|
145
145
|
- lib/relaton/render/iso690/i18n/fr.yml
|
|
146
|
+
- lib/relaton/render/iso690/i18n/ja.yml
|
|
146
147
|
- lib/relaton/render/iso690/identifier_kinds.rb
|
|
147
148
|
- lib/relaton/render/iso690/index_renderer.rb
|
|
148
149
|
- lib/relaton/render/iso690/kinds.rb
|