BabelDOC 0.1.17__tar.gz → 0.1.19__tar.gz
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.
- {babeldoc-0.1.17 → babeldoc-0.1.19}/PKG-INFO +6 -1
- {babeldoc-0.1.17 → babeldoc-0.1.19}/README.md +5 -0
- babeldoc-0.1.19/babeldoc/__init__.py +1 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/const.py +1 -1
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/backend/pdf_creater.py +15 -15
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/midend/typesetting.py +130 -20
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/high_level.py +1 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/main.py +1 -1
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/pdfinterp.py +7 -1
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/translation_config.py +9 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/pyproject.toml +2 -2
- {babeldoc-0.1.17 → babeldoc-0.1.19}/uv.lock +1 -1
- babeldoc-0.1.17/babeldoc/__init__.py +0 -1
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.cursorignore +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/dependabot.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/labels.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/release-drafter.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/workflows/codeql.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/workflows/docs.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/workflows/labeler.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/workflows/publish-to-pypi.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.github/workflows/test.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.gitignore +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/.pre-commit-config.yaml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/LICENSE +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/asynchronize/__init__.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/converter.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/__init__.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/backend/__init__.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/frontend/__init__.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/frontend/il_creater.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/il_version_1.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/il_version_1.rnc +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/il_version_1.rng +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/il_version_1.xsd +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/midend/__init__.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/midend/add_debug_information.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/midend/il_translator.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/midend/layout_parser.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/midend/paragraph_finder.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/midend/remove_descent.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/midend/styles_and_formulas.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/translator/__init__.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/translator/cache.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/translator/translator.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/utils/fontmap.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/utils/layout_helper.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/utils/style_helper.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/document_il/xml_converter.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/docvision/README.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/docvision/__init__.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/docvision/doclayout.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/docvision/rpc_doclayout.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/babeldoc/progress_monitor.py +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/CODE_OF_CONDUCT.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/CONTRIBUTING.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/CONTRIBUTOR_REWARD.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/ILTranslator/ILTranslator.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/PDFCreation/PDFCreation.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/PDFParsing/PDFParsing.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/README.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/StylesAndFormulas/StylesAndFormulas.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/Typesetting/Typesetting.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/README.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/deploy.sh +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/images/babeldoc-banner.png +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/images/babeldoc-contributor_reward_example.png +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/images/babeldoc-preview.gif +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/index.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/intro-to-pdf-object.md +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/docs/requirements.txt +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/mkdocs.yml +0 -0
- {babeldoc-0.1.17 → babeldoc-0.1.19}/tests/test_translation_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BabelDOC
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.19
|
|
4
4
|
Summary: Yet Another Document Translator
|
|
5
5
|
Project-URL: Homepage, https://github.com/funstory-ai/BabelDOC
|
|
6
6
|
Project-URL: Issues, https://github.com/funstory-ai/BabelDOC/issues
|
|
@@ -58,6 +58,7 @@ Description-Content-Type: text/markdown
|
|
|
58
58
|
|
|
59
59
|
PDF scientific paper translation and bilingual comparison library.
|
|
60
60
|
|
|
61
|
+
- Beta version launched [Immersive Translate - BabelDOC](https://app.immersivetranslate.com/babel-doc/) 1000 free pages per month.
|
|
61
62
|
- Provides a simple [command line interface](#getting-started).
|
|
62
63
|
- Provides a [Python API](#python-api).
|
|
63
64
|
- Mainly designed to be embedded into other programs, but can also be used directly for simple translation tasks.
|
|
@@ -133,6 +134,10 @@ uv run babeldoc --bing --files example.pdf --files example2.pdf
|
|
|
133
134
|
|
|
134
135
|
> [!TIP]
|
|
135
136
|
> Currently, this project mainly focuses on English-to-Chinese translation, and other scenarios have not been tested yet.
|
|
137
|
+
>
|
|
138
|
+
> (2025.3.1 update): Basic English target language support has been added, primarily to minimize line breaks within words([0-9A-Za-z]+).
|
|
139
|
+
>
|
|
140
|
+
> [HELP WANTED: Collecting word regular expressions for more languages](https://github.com/funstory-ai/BabelDOC/issues/129)
|
|
136
141
|
|
|
137
142
|
### PDF Processing Options
|
|
138
143
|
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
PDF scientific paper translation and bilingual comparison library.
|
|
26
26
|
|
|
27
|
+
- Beta version launched [Immersive Translate - BabelDOC](https://app.immersivetranslate.com/babel-doc/) 1000 free pages per month.
|
|
27
28
|
- Provides a simple [command line interface](#getting-started).
|
|
28
29
|
- Provides a [Python API](#python-api).
|
|
29
30
|
- Mainly designed to be embedded into other programs, but can also be used directly for simple translation tasks.
|
|
@@ -99,6 +100,10 @@ uv run babeldoc --bing --files example.pdf --files example2.pdf
|
|
|
99
100
|
|
|
100
101
|
> [!TIP]
|
|
101
102
|
> Currently, this project mainly focuses on English-to-Chinese translation, and other scenarios have not been tested yet.
|
|
103
|
+
>
|
|
104
|
+
> (2025.3.1 update): Basic English target language support has been added, primarily to minimize line breaks within words([0-9A-Za-z]+).
|
|
105
|
+
>
|
|
106
|
+
> [HELP WANTED: Collecting word regular expressions for more languages](https://github.com/funstory-ai/BabelDOC/issues/129)
|
|
102
107
|
|
|
103
108
|
### PDF Processing Options
|
|
104
109
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.19"
|
|
@@ -413,11 +413,11 @@ class PDFCreater:
|
|
|
413
413
|
|
|
414
414
|
# 使用子进程进行字体子集化
|
|
415
415
|
if not translation_config.skip_clean:
|
|
416
|
-
pdf = self.subset_fonts_in_subprocess(pdf, translation_config)
|
|
416
|
+
pdf = self.subset_fonts_in_subprocess(pdf, translation_config, tag="debug")
|
|
417
417
|
return pdf
|
|
418
418
|
|
|
419
419
|
def subset_fonts_in_subprocess(
|
|
420
|
-
self, pdf: pymupdf.Document, translation_config: TranslationConfig
|
|
420
|
+
self, pdf: pymupdf.Document, translation_config: TranslationConfig, tag: str
|
|
421
421
|
) -> pymupdf.Document:
|
|
422
422
|
"""Run font subsetting in a subprocess with timeout.
|
|
423
423
|
|
|
@@ -431,14 +431,10 @@ class PDFCreater:
|
|
|
431
431
|
original_pdf = pdf
|
|
432
432
|
# Create temporary file paths
|
|
433
433
|
temp_input = str(
|
|
434
|
-
translation_config.get_working_file_path(
|
|
435
|
-
f"temp_subset_input_{int(time.time())}.pdf"
|
|
436
|
-
)
|
|
434
|
+
translation_config.get_working_file_path(f"temp_subset_input_{tag}.pdf")
|
|
437
435
|
)
|
|
438
436
|
temp_output = str(
|
|
439
|
-
translation_config.get_working_file_path(
|
|
440
|
-
f"temp_subset_output_{int(time.time())}.pdf"
|
|
441
|
-
)
|
|
437
|
+
translation_config.get_working_file_path(f"temp_subset_output_{tag}.pdf")
|
|
442
438
|
)
|
|
443
439
|
|
|
444
440
|
# Save PDF to temporary file without subsetting
|
|
@@ -504,6 +500,7 @@ class PDFCreater:
|
|
|
504
500
|
deflate_fonts: bool = True,
|
|
505
501
|
linear: bool = False,
|
|
506
502
|
timeout: int = 120,
|
|
503
|
+
tag: str = "",
|
|
507
504
|
) -> bool:
|
|
508
505
|
"""Save a PDF document with a timeout for the clean=True operation.
|
|
509
506
|
|
|
@@ -523,14 +520,10 @@ class PDFCreater:
|
|
|
523
520
|
"""
|
|
524
521
|
# Create temporary file paths
|
|
525
522
|
temp_input = str(
|
|
526
|
-
translation_config.get_working_file_path(
|
|
527
|
-
f"temp_save_input_{int(time.time())}.pdf"
|
|
528
|
-
)
|
|
523
|
+
translation_config.get_working_file_path(f"temp_save_input_{tag}.pdf")
|
|
529
524
|
)
|
|
530
525
|
temp_output = str(
|
|
531
|
-
translation_config.get_working_file_path(
|
|
532
|
-
f"temp_save_output_{int(time.time())}.pdf"
|
|
533
|
-
)
|
|
526
|
+
translation_config.get_working_file_path(f"temp_save_output_{tag}.pdf")
|
|
534
527
|
)
|
|
535
528
|
|
|
536
529
|
# Save PDF to temporary file first
|
|
@@ -614,6 +607,9 @@ class PDFCreater:
|
|
|
614
607
|
logger.error(f"Error copying saved PDF: {e}")
|
|
615
608
|
pdf.save(output_path) # Fallback to direct save
|
|
616
609
|
return False
|
|
610
|
+
finally:
|
|
611
|
+
Path(temp_input).unlink()
|
|
612
|
+
Path(temp_output).unlink()
|
|
617
613
|
else:
|
|
618
614
|
logger.warning(
|
|
619
615
|
f"PDF save with clean=True failed with exit code {exit_code} or produced empty file"
|
|
@@ -748,7 +744,9 @@ class PDFCreater:
|
|
|
748
744
|
1,
|
|
749
745
|
) as pbar:
|
|
750
746
|
if not translation_config.skip_clean:
|
|
751
|
-
pdf = self.subset_fonts_in_subprocess(
|
|
747
|
+
pdf = self.subset_fonts_in_subprocess(
|
|
748
|
+
pdf, translation_config, tag="mono"
|
|
749
|
+
)
|
|
752
750
|
|
|
753
751
|
pbar.advance()
|
|
754
752
|
with self.translation_config.progress_monitor.stage_start(
|
|
@@ -773,6 +771,7 @@ class PDFCreater:
|
|
|
773
771
|
clean=not translation_config.skip_clean,
|
|
774
772
|
deflate_fonts=True,
|
|
775
773
|
linear=False,
|
|
774
|
+
tag="mono",
|
|
776
775
|
)
|
|
777
776
|
pbar.advance()
|
|
778
777
|
dual_out_path = None
|
|
@@ -823,6 +822,7 @@ class PDFCreater:
|
|
|
823
822
|
clean=not translation_config.skip_clean,
|
|
824
823
|
deflate_fonts=True,
|
|
825
824
|
linear=False,
|
|
825
|
+
tag="dual",
|
|
826
826
|
)
|
|
827
827
|
if translation_config.debug:
|
|
828
828
|
translation_config.raise_if_cancelled()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import re
|
|
2
3
|
import statistics
|
|
3
4
|
import unicodedata
|
|
4
5
|
from functools import cache
|
|
@@ -83,6 +84,15 @@ class TypesettingUnit:
|
|
|
83
84
|
]
|
|
84
85
|
return False
|
|
85
86
|
|
|
87
|
+
@property
|
|
88
|
+
def can_break_line(self):
|
|
89
|
+
unicode = self.try_get_unicode()
|
|
90
|
+
if not unicode:
|
|
91
|
+
return True
|
|
92
|
+
if re.match(r"^[a-zA-Z0-9]+$", unicode):
|
|
93
|
+
return False
|
|
94
|
+
return True
|
|
95
|
+
|
|
86
96
|
@property
|
|
87
97
|
def is_chinese_char(self):
|
|
88
98
|
if self.formular:
|
|
@@ -146,33 +156,85 @@ class TypesettingUnit:
|
|
|
146
156
|
|
|
147
157
|
if unicode:
|
|
148
158
|
return unicode in [
|
|
159
|
+
# 英文标点
|
|
149
160
|
",",
|
|
150
161
|
".",
|
|
151
162
|
":",
|
|
152
163
|
";",
|
|
153
164
|
"?",
|
|
154
165
|
"!",
|
|
155
|
-
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
|
|
172
|
-
"
|
|
166
|
+
# 中文点号
|
|
167
|
+
",", # 逗号
|
|
168
|
+
"。", # 句号
|
|
169
|
+
".", # 全角句号
|
|
170
|
+
"、", # 顿号
|
|
171
|
+
":", # 冒号
|
|
172
|
+
";", # 分号
|
|
173
|
+
"!", # 叹号
|
|
174
|
+
"‼", # 双叹号
|
|
175
|
+
"?", # 问号
|
|
176
|
+
"⁇", # 双问号
|
|
177
|
+
# 结束引号
|
|
178
|
+
"”", # 右双引号
|
|
179
|
+
"’", # 右单引号
|
|
180
|
+
"」", # 右直角单引号
|
|
181
|
+
"』", # 右直角双引号
|
|
182
|
+
# 结束括号
|
|
183
|
+
")", # 右圆括号
|
|
184
|
+
"]", # 右方括号
|
|
185
|
+
"}", # 右花括号
|
|
186
|
+
")", # 右圆括号
|
|
187
|
+
"〕", # 右龟甲括号
|
|
188
|
+
"〉", # 右单书名号
|
|
189
|
+
"】", # 右黑色方头括号
|
|
190
|
+
"〗", # 右空白方头括号
|
|
191
|
+
"]", # 全角右方括号
|
|
192
|
+
"}", # 全角右花括号
|
|
193
|
+
# 结束双书名号
|
|
194
|
+
"》", # 右双书名号
|
|
195
|
+
# 连接号
|
|
196
|
+
"~", # 全角波浪号
|
|
197
|
+
"-", # 连字符减号
|
|
198
|
+
"–", # 短破折号(EN DASH)
|
|
199
|
+
"—", # 长破折号(EM DASH)
|
|
200
|
+
# 间隔号
|
|
201
|
+
"·", # 中间点
|
|
202
|
+
"・", # 片假名中间点
|
|
203
|
+
"‧", # 连字点
|
|
204
|
+
# 分隔号
|
|
205
|
+
"/", # 斜杠
|
|
206
|
+
"/", # 全角斜杠
|
|
207
|
+
"⁄", # 分数斜杠
|
|
173
208
|
]
|
|
174
209
|
return False
|
|
175
210
|
|
|
211
|
+
@property
|
|
212
|
+
def is_cannot_appear_in_line_end_punctuation(self):
|
|
213
|
+
if self.formular:
|
|
214
|
+
return False
|
|
215
|
+
unicode = self.try_get_unicode()
|
|
216
|
+
if not unicode:
|
|
217
|
+
return False
|
|
218
|
+
return unicode in [
|
|
219
|
+
# 开始引号
|
|
220
|
+
"“", # 左双引号
|
|
221
|
+
"‘", # 左单引号
|
|
222
|
+
"「", # 左直角单引号
|
|
223
|
+
"『", # 左直角双引号
|
|
224
|
+
# 开始括号
|
|
225
|
+
"(", # 左圆括号
|
|
226
|
+
"[", # 左方括号
|
|
227
|
+
"{", # 左花括号
|
|
228
|
+
"(", # 左圆括号
|
|
229
|
+
"〔", # 左龟甲括号
|
|
230
|
+
"〈", # 左单书名号
|
|
231
|
+
"《", # 左双书名号
|
|
232
|
+
# 开始单双书名号
|
|
233
|
+
"〖", # 左空白方头括号
|
|
234
|
+
"〘", # 左黑色方头括号
|
|
235
|
+
"〚", # 左单书名号
|
|
236
|
+
]
|
|
237
|
+
|
|
176
238
|
def passthrough(self) -> [PdfCharacter]:
|
|
177
239
|
if self.char:
|
|
178
240
|
return [self.char]
|
|
@@ -450,6 +512,21 @@ class Typesetting:
|
|
|
450
512
|
paragraph.pdf_paragraph_composition = []
|
|
451
513
|
self.retypeset(paragraph, page, typesetting_units)
|
|
452
514
|
|
|
515
|
+
def _get_width_before_next_break_point(
|
|
516
|
+
self, typesetting_units: list[TypesettingUnit], scale: float
|
|
517
|
+
) -> float:
|
|
518
|
+
if not typesetting_units:
|
|
519
|
+
return 0
|
|
520
|
+
if typesetting_units[0].can_break_line:
|
|
521
|
+
return 0
|
|
522
|
+
|
|
523
|
+
total_width = 0
|
|
524
|
+
for unit in typesetting_units:
|
|
525
|
+
if unit.can_break_line:
|
|
526
|
+
return total_width * scale
|
|
527
|
+
total_width += unit.width
|
|
528
|
+
return total_width * scale
|
|
529
|
+
|
|
453
530
|
def _layout_typesetting_units(
|
|
454
531
|
self,
|
|
455
532
|
typesetting_units: list[TypesettingUnit],
|
|
@@ -457,6 +534,7 @@ class Typesetting:
|
|
|
457
534
|
scale: float,
|
|
458
535
|
line_spacing: float,
|
|
459
536
|
paragraph: il_version_1.PdfParagraph,
|
|
537
|
+
use_english_line_break: bool = True,
|
|
460
538
|
) -> tuple[list[TypesettingUnit], bool]:
|
|
461
539
|
"""布局排版单元。
|
|
462
540
|
|
|
@@ -504,7 +582,7 @@ class Typesetting:
|
|
|
504
582
|
if paragraph.first_line_indent:
|
|
505
583
|
current_x += space_width * 4
|
|
506
584
|
# 遍历所有排版单元
|
|
507
|
-
for unit in typesetting_units:
|
|
585
|
+
for i, unit in enumerate(typesetting_units):
|
|
508
586
|
# 计算当前单元在当前缩放下的尺寸
|
|
509
587
|
unit_width = unit.width * scale
|
|
510
588
|
unit_height = unit.height * scale
|
|
@@ -528,11 +606,36 @@ class Typesetting:
|
|
|
528
606
|
and current_x > box.x # 不是行首
|
|
529
607
|
and unit.try_get_unicode() != " " # 不是空格
|
|
530
608
|
and last_unit.try_get_unicode() != " " # 不是空格
|
|
609
|
+
and last_unit.try_get_unicode()
|
|
610
|
+
not in [
|
|
611
|
+
"。",
|
|
612
|
+
"!",
|
|
613
|
+
"?",
|
|
614
|
+
";",
|
|
615
|
+
":",
|
|
616
|
+
",",
|
|
617
|
+
]
|
|
531
618
|
):
|
|
532
619
|
current_x += space_width * 0.5
|
|
620
|
+
if use_english_line_break:
|
|
621
|
+
width_before_next_break_point = self._get_width_before_next_break_point(
|
|
622
|
+
typesetting_units[i + 1 :], scale
|
|
623
|
+
)
|
|
624
|
+
else:
|
|
625
|
+
width_before_next_break_point = 0
|
|
533
626
|
|
|
534
627
|
# 如果当前行放不下这个元素,换行
|
|
535
|
-
if
|
|
628
|
+
if not unit.is_hung_punctuation and (
|
|
629
|
+
(current_x + unit_width > box.x2)
|
|
630
|
+
or (
|
|
631
|
+
use_english_line_break
|
|
632
|
+
and current_x + unit_width + width_before_next_break_point > box.x2
|
|
633
|
+
)
|
|
634
|
+
or (
|
|
635
|
+
unit.is_cannot_appear_in_line_end_punctuation
|
|
636
|
+
and current_x + unit_width * 2 > box.x2
|
|
637
|
+
)
|
|
638
|
+
):
|
|
536
639
|
# 换行
|
|
537
640
|
current_x = box.x
|
|
538
641
|
current_y -= line_height * line_spacing
|
|
@@ -568,6 +671,7 @@ class Typesetting:
|
|
|
568
671
|
paragraph: il_version_1.PdfParagraph,
|
|
569
672
|
page: il_version_1.Page,
|
|
570
673
|
typesetting_units: list[TypesettingUnit],
|
|
674
|
+
use_english_line_break: bool = True,
|
|
571
675
|
):
|
|
572
676
|
box = paragraph.box
|
|
573
677
|
scale = 1.0
|
|
@@ -584,6 +688,7 @@ class Typesetting:
|
|
|
584
688
|
scale,
|
|
585
689
|
line_spacing,
|
|
586
690
|
paragraph,
|
|
691
|
+
use_english_line_break,
|
|
587
692
|
)
|
|
588
693
|
|
|
589
694
|
# 如果所有单元都放得下,就完成排版
|
|
@@ -629,6 +734,11 @@ class Typesetting:
|
|
|
629
734
|
min_line_spacing = 1.1
|
|
630
735
|
scale = 1.0
|
|
631
736
|
line_spacing = 1.5
|
|
737
|
+
# 如果仍然放不下,则尝试去除英文换行限制
|
|
738
|
+
if use_english_line_break:
|
|
739
|
+
self.retypeset(
|
|
740
|
+
paragraph, page, typesetting_units, use_english_line_break=False
|
|
741
|
+
)
|
|
632
742
|
|
|
633
743
|
def create_typesetting_units(
|
|
634
744
|
self,
|
|
@@ -249,7 +249,13 @@ class PDFPageInterpreterEx(PDFPageInterpreter):
|
|
|
249
249
|
subtype = xobj.get("Subtype")
|
|
250
250
|
if subtype is LITERAL_FORM and "BBox" in xobj:
|
|
251
251
|
interpreter = self.dup()
|
|
252
|
-
|
|
252
|
+
|
|
253
|
+
# In extremely rare cases, a none might be mixed in the bbox, for example
|
|
254
|
+
# /BBox [ 0 3.052 null 274.9 157.3 ]
|
|
255
|
+
bbox = list(
|
|
256
|
+
filter(lambda x: x is not None, cast(Rect, list_value(xobj["BBox"])))
|
|
257
|
+
)
|
|
258
|
+
|
|
253
259
|
matrix = cast(Matrix, list_value(xobj.get("Matrix", MATRIX_IDENTITY)))
|
|
254
260
|
# According to PDF reference 1.7 section 4.9.1, XObjects in
|
|
255
261
|
# earlier PDFs (prior to v1.2) use the page's Resources entry
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import shutil
|
|
1
3
|
import tempfile
|
|
2
4
|
import threading
|
|
3
5
|
from pathlib import Path
|
|
@@ -7,6 +9,8 @@ from babeldoc.document_il.translator.translator import BaseTranslator
|
|
|
7
9
|
from babeldoc.docvision.doclayout import DocLayoutModel
|
|
8
10
|
from babeldoc.progress_monitor import ProgressMonitor
|
|
9
11
|
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
class TranslationConfig:
|
|
12
16
|
def __init__(
|
|
@@ -158,6 +162,11 @@ class TranslationConfig:
|
|
|
158
162
|
if self.progress_monitor is not None:
|
|
159
163
|
self.progress_monitor.cancel()
|
|
160
164
|
|
|
165
|
+
def cleanup_temp_files(self):
|
|
166
|
+
if self._is_temp_dir:
|
|
167
|
+
logger.info(f"cleanup temp files: {self.working_dir}")
|
|
168
|
+
shutil.rmtree(self.working_dir)
|
|
169
|
+
|
|
161
170
|
|
|
162
171
|
class TranslateResult:
|
|
163
172
|
original_pdf_path: str
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "BabelDOC"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.19"
|
|
4
4
|
description = "Yet Another Document Translator"
|
|
5
5
|
license = "AGPL-3.0"
|
|
6
6
|
readme = "README.md"
|
|
@@ -132,7 +132,7 @@ pythonpath = [".", "src"]
|
|
|
132
132
|
testpaths = ["tests"]
|
|
133
133
|
|
|
134
134
|
[bumpver]
|
|
135
|
-
current_version = "0.1.
|
|
135
|
+
current_version = "0.1.19"
|
|
136
136
|
version_pattern = "MAJOR.MINOR.PATCH[.PYTAGNUM]"
|
|
137
137
|
|
|
138
138
|
[bumpver.file_patterns]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.17"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{babeldoc-0.1.17 → babeldoc-0.1.19}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|