prawn_hebrew 0.1.7 → 0.2.0
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/prawn_hebrew.rb +158 -11
- data/lib/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 223562a63ced0cedfc7d8b64ddae8408b3302a57676fa97ef100bf7266cf7203
|
|
4
|
+
data.tar.gz: ec4ee45cf9a40979dcbc63d37ee914ef34520a80604b62a984b0eabc4556b535
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d99416beb3197fe6ab2955447f9319c41a5d074bc230ec7e56acdb30fcb6701d27cd5c850308c1c24c1e48e1c649af947dba886a68c1db68913aec12bfcbb07e
|
|
7
|
+
data.tar.gz: e4edc4bf10ff2395ae65b2f07269ab5e53c7d42adb9080ba62b0fa7f64567c6e176f3b050a0b429072d0734b6e52c4ca1727a8694c5b5c802c46220022d3060a
|
data/lib/prawn_hebrew.rb
CHANGED
|
@@ -2,21 +2,78 @@ require 'prawn'
|
|
|
2
2
|
require_relative 'version'
|
|
3
3
|
|
|
4
4
|
module PrawnHebrew
|
|
5
|
+
# Simple wrapper class for Hebrew text in table cells
|
|
6
|
+
class HebrewTableCell
|
|
7
|
+
attr_reader :text
|
|
8
|
+
|
|
9
|
+
def initialize(text, hebrew_text: false)
|
|
10
|
+
@text = text
|
|
11
|
+
@hebrew_text = hebrew_text
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
@text.to_s
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
5
19
|
module Text
|
|
6
20
|
DEFAULT_HEBREW_FONT = 'GveretLevinHebrew'.freeze
|
|
7
21
|
DEFAULT_ENGLISH_FONT = 'Helvetica'.freeze
|
|
8
22
|
|
|
9
23
|
# Set to true for debugging which text rendering path is used
|
|
10
24
|
DEBUG_MODE = false
|
|
11
|
-
|
|
12
|
-
|
|
25
|
+
|
|
26
|
+
# Characters that should be removed or replaced to prevent Prawn errors
|
|
27
|
+
# Zero-width and invisible characters
|
|
28
|
+
INVISIBLE_CHARS = /[\u200B\u200C\u200D\u200E\u200F\uFEFF\u00AD\u202A\u202B\u202C\u202D\u202E\u2060\u2061\u2062\u2063\u2064\u206A\u206B\u206C\u206D\u206E\u206F]/.freeze
|
|
29
|
+
|
|
30
|
+
# Non-breaking spaces (replace with regular space)
|
|
31
|
+
NBSP_CHARS = /[\u00A0\u202F\u2007\u2008\u2009\u200A\u205F\u3000]/.freeze
|
|
32
|
+
|
|
33
|
+
# Dashes - em dash, en dash, figure dash, horizontal bar, etc. (replace with regular hyphen)
|
|
34
|
+
DASH_CHARS = /[\u2010\u2011\u2012\u2013\u2014\u2015\u2212\uFE58\uFE63\uFF0D]/.freeze
|
|
35
|
+
|
|
36
|
+
# Quotation marks (replace with standard quotes)
|
|
37
|
+
SMART_QUOTES_DOUBLE = /[\u201C\u201D\u201E\u201F\u00AB\u00BB\u301D\u301E\u301F]/.freeze
|
|
38
|
+
SMART_QUOTES_SINGLE = /[\u2018\u2019\u201A\u201B\u2039\u203A]/.freeze
|
|
39
|
+
|
|
40
|
+
# Ellipsis (replace with three dots)
|
|
41
|
+
ELLIPSIS_CHAR = /\u2026/.freeze
|
|
42
|
+
|
|
43
|
+
# Arrows and special symbols (replace with text equivalents)
|
|
44
|
+
ARROW_CHAR = /\u2192/.freeze # → (rightward arrow)
|
|
45
|
+
LEFT_ARROW = /\u2190/.freeze # ←
|
|
46
|
+
UP_ARROW = /\u2191/.freeze # ↑
|
|
47
|
+
DOWN_ARROW = /\u2193/.freeze # ↓
|
|
48
|
+
|
|
49
|
+
# Bullet points and list markers
|
|
50
|
+
BULLET_CHARS = /[\u2022\u2023\u2043\u204C\u204D\u2219\u25E6\u25AA\u25AB\u25CF\u25CB]/.freeze
|
|
51
|
+
|
|
52
|
+
# Other problematic characters
|
|
53
|
+
MISC_PROBLEM_CHARS = /[\u2028\u2029\uFFFC\uFFFD\uFFFF]/.freeze # line/paragraph separators, object replacement, replacement char
|
|
54
|
+
|
|
55
|
+
# Punctuation that should stay at the end of Hebrew text (rendered after in RTL)
|
|
56
|
+
TRAILING_PUNCTUATION = /([.,:;!?\-\u05BE\u05C3]+)$/.freeze # includes Hebrew punctuation
|
|
57
|
+
LEADING_PUNCTUATION = /^([.,:;!?\-\u05BE\u05C3()\[\]{}]+)/.freeze
|
|
13
58
|
|
|
14
59
|
|
|
15
60
|
|
|
16
61
|
|
|
17
62
|
def sanitize_text(text)
|
|
18
63
|
return text if text.nil?
|
|
19
|
-
text.to_s
|
|
64
|
+
text.to_s
|
|
65
|
+
.gsub(INVISIBLE_CHARS, '') # Remove invisible characters completely
|
|
66
|
+
.gsub(NBSP_CHARS, ' ') # Replace non-breaking spaces with regular space
|
|
67
|
+
.gsub(DASH_CHARS, '-') # Replace all dash types with regular hyphen
|
|
68
|
+
.gsub(SMART_QUOTES_DOUBLE, '"') # Replace smart double quotes
|
|
69
|
+
.gsub(SMART_QUOTES_SINGLE, "'") # Replace smart single quotes
|
|
70
|
+
.gsub(ELLIPSIS_CHAR, '...') # Replace ellipsis with three dots
|
|
71
|
+
.gsub(ARROW_CHAR, '->') # Replace right arrow
|
|
72
|
+
.gsub(LEFT_ARROW, '<-') # Replace left arrow
|
|
73
|
+
.gsub(UP_ARROW, '^') # Replace up arrow
|
|
74
|
+
.gsub(DOWN_ARROW, 'v') # Replace down arrow
|
|
75
|
+
.gsub(BULLET_CHARS, '*') # Replace bullets with asterisk
|
|
76
|
+
.gsub(MISC_PROBLEM_CHARS, '') # Remove other problematic chars
|
|
20
77
|
end
|
|
21
78
|
|
|
22
79
|
def hebrew_formatted_text(text, size: 12, style: :normal, hebrew_font: DEFAULT_HEBREW_FONT, english_font: DEFAULT_ENGLISH_FONT)
|
|
@@ -42,10 +99,8 @@ module PrawnHebrew
|
|
|
42
99
|
hebrew_run << word
|
|
43
100
|
else
|
|
44
101
|
unless hebrew_run.empty?
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
all_fragments << { text: ' ', font: hebrew_font, size: size, direction: :rtl, styles: styles } if idx < hebrew_run.length - 1
|
|
48
|
-
end
|
|
102
|
+
# Process Hebrew run and handle trailing punctuation
|
|
103
|
+
process_hebrew_run(hebrew_run, all_fragments, hebrew_font, english_font, size, styles)
|
|
49
104
|
all_fragments << { text: ' ' }
|
|
50
105
|
hebrew_run.clear
|
|
51
106
|
end
|
|
@@ -54,10 +109,8 @@ module PrawnHebrew
|
|
|
54
109
|
end
|
|
55
110
|
|
|
56
111
|
unless hebrew_run.empty?
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
all_fragments << { text: ' ', font: hebrew_font, size: size, direction: :rtl, styles: styles } if idx < hebrew_run.length - 1
|
|
60
|
-
end
|
|
112
|
+
# Process remaining Hebrew run
|
|
113
|
+
process_hebrew_run(hebrew_run, all_fragments, hebrew_font, english_font, size, styles)
|
|
61
114
|
end
|
|
62
115
|
|
|
63
116
|
# Add newline between lines (except after the last line)
|
|
@@ -68,12 +121,84 @@ module PrawnHebrew
|
|
|
68
121
|
|
|
69
122
|
all_fragments
|
|
70
123
|
end
|
|
124
|
+
|
|
125
|
+
# Process a run of Hebrew words, handling punctuation correctly
|
|
126
|
+
def process_hebrew_run(hebrew_run, all_fragments, hebrew_font, english_font, size, styles)
|
|
127
|
+
# Check if the last word in the run has trailing punctuation
|
|
128
|
+
last_word = hebrew_run.last
|
|
129
|
+
trailing_punct = nil
|
|
130
|
+
|
|
131
|
+
if last_word =~ TRAILING_PUNCTUATION
|
|
132
|
+
trailing_punct = $1
|
|
133
|
+
# Remove trailing punctuation from the last word
|
|
134
|
+
hebrew_run[-1] = last_word.sub(TRAILING_PUNCTUATION, '')
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Check if the first word has leading punctuation (for RTL, this appears at the end)
|
|
138
|
+
first_word = hebrew_run.first
|
|
139
|
+
leading_punct = nil
|
|
140
|
+
|
|
141
|
+
if first_word =~ LEADING_PUNCTUATION
|
|
142
|
+
leading_punct = $1
|
|
143
|
+
hebrew_run[0] = first_word.sub(LEADING_PUNCTUATION, '')
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Add leading punctuation first (it will appear at the visual end due to RTL)
|
|
147
|
+
if leading_punct
|
|
148
|
+
all_fragments << { text: leading_punct, font: english_font, size: size, styles: styles }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Reverse Hebrew words for RTL display
|
|
152
|
+
hebrew_run.reverse.each_with_index do |hw, idx|
|
|
153
|
+
next if hw.empty?
|
|
154
|
+
all_fragments << { text: hw, font: hebrew_font, size: size, direction: :rtl, styles: styles }
|
|
155
|
+
all_fragments << { text: ' ', font: hebrew_font, size: size, direction: :rtl, styles: styles } if idx < hebrew_run.length - 1
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Add trailing punctuation at the end (it will appear at the visual end of Hebrew text)
|
|
159
|
+
if trailing_punct
|
|
160
|
+
all_fragments << { text: trailing_punct, font: english_font, size: size, styles: styles }
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def hebrew_table(data, size: 12, style: :normal,
|
|
165
|
+
hebrew_font: DEFAULT_HEBREW_FONT,
|
|
166
|
+
english_font: DEFAULT_ENGLISH_FONT,
|
|
167
|
+
**table_opts)
|
|
168
|
+
# Process each row: sanitize and render Hebrew cells using formatted text
|
|
169
|
+
processed_data = data.map do |row|
|
|
170
|
+
row.map do |cell_content|
|
|
171
|
+
sanitize_text(cell_content.to_s)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Create table with a block to apply Hebrew formatting to cells
|
|
176
|
+
table(processed_data, table_opts) do |table|
|
|
177
|
+
# Apply Hebrew formatting to cells that contain Hebrew text
|
|
178
|
+
table.cells.each do |cell|
|
|
179
|
+
cell_text = cell.content
|
|
180
|
+
if cell_text =~ /\p{Hebrew}/
|
|
181
|
+
# Use text_color and font to support Hebrew
|
|
182
|
+
cell.font = hebrew_font
|
|
183
|
+
cell.size = size
|
|
184
|
+
cell.text_color = table_opts[:text_color] || "000000"
|
|
185
|
+
else
|
|
186
|
+
# English cells
|
|
187
|
+
cell.font = english_font
|
|
188
|
+
cell.size = size
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
71
193
|
|
|
72
194
|
def hebrew_text_box(text, size: 12, style: :normal,
|
|
73
195
|
hebrew_font: DEFAULT_HEBREW_FONT,
|
|
74
196
|
english_font: DEFAULT_ENGLISH_FONT,
|
|
75
197
|
direction: :auto, **box_opts)
|
|
76
198
|
|
|
199
|
+
# Sanitize text first to remove problematic characters
|
|
200
|
+
text = sanitize_text(text)
|
|
201
|
+
|
|
77
202
|
# Handle font specification in box_opts or use defaults
|
|
78
203
|
final_hebrew_font = box_opts.delete(:hebrew_font) || hebrew_font
|
|
79
204
|
final_english_font = box_opts.delete(:english_font) || english_font
|
|
@@ -223,6 +348,28 @@ module PrawnHebrew
|
|
|
223
348
|
end
|
|
224
349
|
end
|
|
225
350
|
end
|
|
351
|
+
|
|
352
|
+
# Helper method to create table cells with Hebrew support
|
|
353
|
+
def hebrew_table_cell(text, size: 12, style: :normal,
|
|
354
|
+
hebrew_font: DEFAULT_HEBREW_FONT,
|
|
355
|
+
english_font: DEFAULT_ENGLISH_FONT,
|
|
356
|
+
**cell_opts)
|
|
357
|
+
# Create a hash that can be used as table cell content
|
|
358
|
+
# with Hebrew text handling
|
|
359
|
+
if text.to_s =~ /\p{Hebrew}/
|
|
360
|
+
{
|
|
361
|
+
content: text,
|
|
362
|
+
hebrew_text: true,
|
|
363
|
+
size: size,
|
|
364
|
+
style: style,
|
|
365
|
+
hebrew_font: hebrew_font,
|
|
366
|
+
english_font: english_font,
|
|
367
|
+
cell_opts: cell_opts
|
|
368
|
+
}
|
|
369
|
+
else
|
|
370
|
+
{ content: text }
|
|
371
|
+
end
|
|
372
|
+
end
|
|
226
373
|
end
|
|
227
374
|
end
|
|
228
375
|
|
data/lib/version.rb
CHANGED