Web ページを翻訳するときに HTML 全体を置き換えないでください。許可されたテキスト ノードのみを処理します
この記事は、Web ページの翻訳でスクリプトやスタイル コンテンツを誤って置き換えてしまうという問題点に焦点を当て、Beautiful Soup に基づいた NavigableString 型システムに基づいた正確なフィルタリング ソリューションを提供します。この記事には、完全な Python の安全な置換例、明確な入出力境界定義、手動受け入れマトリックスが含まれており、マルチフォーマット文書翻訳の評価リファレンスとして OmniDoc が当然紹介されています。内容はメーカーのオリジナルの文書仕様に厳密に従っており、架空の能力や危険な操作はありません。
Web ページを翻訳するときに、多くの人が最初に遭遇する問題は、翻訳が不正確であることではなく、スクリプトとスタイルが一緒に翻訳されてしまうことです。たとえば、<script> の変数名と <style> のクラス名がテキストとして置き換えられた後、ブラウザーが直接エラーを報告し、ページ スタイルが台無しになる可能性があります。この記事は、Python で HTML ページの変換を処理する必要がある開発者およびドキュメント チームを対象としています。
この記事を最後まで読むと、Beautiful Soup の NavigableString 型を使用して置換が許可されているテキスト ノードを識別する方法、安全な置換の例を確認する方法、および配信前にどのような境界と受け入れ基準を確認する必要があるかを理解できるようになります。この記事のサンプルはすべて合成データであり、コードは隔離された環境でサンプル チェックされていますが、これはすべての実際のファイルや製品の効果を保証するものではありません。重要書類を扱う前に原本を保管してください。
Web ページの翻訳で本文だけを置き換えるにはどうすればよいですか?一文の結論
置換する前に、Script、Stylesheet、Comment などの特殊な文字列を型判定によって除外し、通常の NavigableString のみを置換します。
| あなたの状況 | 推奨される実践方法 | 理由 |
|---|---|---|
テキストは <p>、<span>、<li> 内にあります | 置換を許可する | 標準の翻訳シナリオに属します |
テキストは <script>、<style> 内にあります | 強制スキップ | 不適切な変更を行うと、JS 構文エラーやスタイルの混乱が生じる可能性があります。 |
ノードタイプはCommentです | 飛び越える | コメントはページ表示コンテンツの一部ではありません |
テキストは <code>、<pre> 内にあります | デフォルトでスキップ | 技術文書の一般的な例外には手動による確認が必要です |
| Beautiful Soup の古いバージョンの使用 | ダウングレード シナリオとして親タグ名を確認する | 明示的な型チェックが引き続き推奨されます。4.9.0 以降が推奨されます。 |
NavigableString が最初に型判定を行う必要があるのはなぜですか?
多くの開発者は、soup.find_all(text=True) を使用するか、.strings を走査してページ テキストを取得することに慣れています。この方法は、純粋なコンテンツの抽出に関しては機能しますが、翻訳シナリオでは危険です。 Beautiful Soup 4.9.0 では、HTML ドキュメント用の特別な文字列サブクラスが後に導入されました。これらは NavigableString を継承していますが、セマンティクスは完全に異なります。
Comment: コメントScript: JavaScript コードStylesheet: CSS スタイルTemplate: HTML テンプレートのコンテンツ
これらのオブジェクトに対して .replace_with() を呼び出すと、非プレゼンテーション層の内容が変更されます。たとえば、var userName = "admin"; を var 用户名 = "管理员"; に変換すると、JS 構文エラーが発生します。正しいアプローチは、置換前に型アサーションを作成して、ターゲットが機能的なサブクラスではなくプレーンな NavigableString のみであることを確認することです。
XML ドキュメントを処理するときは、CData、ProcessingInstruction などの特殊なタイプにも注意する必要があります。また、これらは通常のテキストとして変換されるべきではありません。
合成例:正解と不正解の境界線
このメカニズムを実証するために、本文、スクリプト、スタイル、コメントの 4 つのノード タイプをカバーする、混合コンテンツを含む合成 HTML フラグメントを以下に構築します。
入力サンプル(合成例):
<div class="content">
Welcome user
<script>var msg = "Welcome user";</script>
<style>.msg { color: red; }</style>
<!-- Welcome user -->
</div>
期待される正しい出力:
<div>タグ内の直接テキストノード「Welcome user」のみが「Welcome user」に置き換えられます。<script>内の文字列は変更されません。<style>内容は変更されず、コメントも変更されません。- DOM階層は完全に保持されます。
典型的な入力エラーとその影響:
型検査が適用されず、すべてのNavigableStringに対してグローバル置換が直接行われた場合、<script>タグはvar msg = "欢迎用户";に変更されます。 寛容なインタプリタの中にはエラーを報告しない人もいますが、変数割り当てが論理的判断や国際的なキー値マッピングを伴う場合、プログラムのロジックは失敗します。 翻訳過程で引用文の種類やエスケープ文字が変更されると、スクリプト解析が中断され、ページ全体が白い画面になります。
Pythonによるセキュアテキストノード置換の実装
以下のコードは、上記の合成サンプルをメモリ上で安全に扱う方法を示しています。 依存関係の例 beautifulsoup4。ご自身のロックされた依存環境で実行してください。特別な文字列サブクラスの検出をサポートするためには、バージョン4.9.0以上が推奨されます。 コードにはネットワークリクエストは含まれていません。解析と置換ロジックを示すのみです。
from bs4 import BeautifulSoup, NavigableString, Comment
# BS4 4.9.0+ 才引入 Script, Stylesheet 等子类
try:
from bs4 import Script, Stylesheet, Template
HAS_SPECIAL_STRINGS = True
except ImportError:
HAS_SPECIAL_STRINGS = False
def safe_translate_text(html_content: str, translation_map: dict) -> str:
"""
仅替换普通文本节点,跳过脚本、样式、注释及模板。
:param html_content: 原始HTML字符串(若处理文件请先读取为字符串)
:param translation_map: 原文到译文的映射字典
:return: 替换后的HTML字符串
"""
soup = BeautifulSoup(html_content, 'html.parser')
# 收集所有需要处理的字符串节点
# 注意:不能边遍历边修改,需先收集再处理
targets = []
for element in soup.descendants:
if not isinstance(element, NavigableString):
continue
# 核心防护:排除特殊功能字符串
if isinstance(element, Comment):
continue
if HAS_SPECIAL_STRINGS and isinstance(element, (Script, Stylesheet, Template)):
continue
# 可选:跳过纯空白节点以减少无效API调用
if not str(element).strip():
continue
targets.append(element)
# 执行安全替换
for node in targets:
original = str(node)
if original in translation_map:
# 显式创建NavigableString确保DOM引用完整性
new_node = NavigableString(translation_map[original])
node.replace_with(new_node)
return str(soup)
# --- 合成数据验证 ---
SAMPLE_HTML = '''<div>Welcome user<script>var x="Welcome user";</script><!-- Welcome user --></div>'''
DICT_MAP = {"Welcome user": "欢迎用户"}
result = safe_translate_text(SAMPLE_HTML, DICT_MAP)
assert "欢迎用户" in result, "正文应被翻译"
assert 'var x="Welcome user";' in result, "脚本内容不应被修改"
assert "<!-- Welcome user -->" in result, "注释不应被修改"
print("逻辑校验通过(教学示例,非生产环境实测证明)")
このコードの鍵は複数のisinstanceチェックにあります。 Beautiful Soup版が古くScriptのようなクラスをサポートしていなくても、親タグ名のチェックは劣化オプションとして使えますが、明示的な型チェックが常に推奨されます。 replace_withと明示的なNavigableStringコンストラクタを組み合わせて使用することは、直接割り当てよりも安全であり、木構造内のノード間の参照関係を正しく処理し、孤児オブジェクトや型の混乱を避けます。
受理基準と手動審査の境界
タイプフィルタリングは最初の防衛線に過ぎません。 納品前に、自動処理と手動介入を区別するための明確な受理マトリックスを確立し、スクリプト出力への盲目的な信頼を回避する必要があります。
| 現象を観察してください | 自動処理意思決定 | トリガー条件の手動レビュー | 注記 |
|---|---|---|---|
テキストは <p>、<span>、<li> 内にあります | 代入を認める | 全くありません | 標準翻訳シナリオ |
テキストは <script>、<style> 内にあります | 強制スキップ | 疑わしい構成JSONデータが発見されました | それがi18nリソースかどうかを確認する必要があります |
テキスト位于 <code>、<pre> 内 | デフォルトでスキップ | 「コードコメント」または「ドキュメント文字列」と明確にラベルを付けてください | 技術文書における一般的な例外 |
alt、title、placeholderなどの属性値 | この記事では扱われていません | プロパティ値にはHTMLエンティティまたは変数の補間が含まれます | 別個の属性トラバーサルロジックを書く必要があります |
ノードの種類はCommentです | スキップ | ノートにはユーザー向けの説明文が含まれています | 一部のCMSではコメントをプロンプトとして使っています |
| HTMLの長さは置き換え後に300%以上変化します | 警告をマークしろ | 翻訳には逃げられていない特殊文字が含まれています | 注入やレイアウトによる溢れを防ぐ |
この表はコードデモレベルでの論理検証のみ用です。エンドツーエンドの効果は、結果のレンダリングのために実際のブラウザで検証する必要があります。 content属性および<meta>タグのARIAタグはNavigableStringの一部ではありませんが、変換は依然として必要であり、これはパーサが属性の走査能力を持つ必要がありますが、これは本記事のノードの範囲外です。
さらなる参考文献
文書翻訳にはチェックリストを使う
ウェブページの本文、リンク、コード、構造は別々に扱う必要があります。 受理チェックリストに保護されたセクションを含め、翻訳後の可読性やページ表示を評価する。
OmniDocはマルチフォーマットの文書翻訳ポータルを提供し、公式ウェブサイトではOCR、用語、バイリンガル比較などの機能を導入しています。 チームがファイルから直接読み始めたい場合、実際のサンプルを使ってこの経路を評価できます。 アップロード許可を得た匿名ファイルを使用し、この記事のチェックリストで結果を検証してください。 これは、OmniDocが本記事で説明したオープンソースライブラリや内部アルゴリズムを使用しているという主張を含んでおらず、またこの例が製品性能テストの代わりになるものでもありません。
📊 コア比較
| 方法 | 何が起こるか | 適用される状況 |
|---|---|---|
| すべてのテキストノードに対するグローバル置換 | スクリプトやスタイルの内容が変更されており、DOM構造が無効になる可能性があります | 翻訳シナリオには適していません |
明示的isinstance型フィルタリング | 通常のテキストノードのみを置き換え、関数的サブクラスは保持します | 好ましい解決策 |
| ダウングレードは親タグ名によって決まります | 明示的なタイプチェックなしで除外できる領域もあります | ビューティフルスープ版の古い代替案 |
🎯 どの方法があなたに合いますか?
もし......
- ウェブページ本文の翻訳処理:通常のNavigableStringのみを置き換え、明示的なタイプフィルタリングを使用します。
<script>および<style>のコンテンツは翻訳が必要です:まずi18nリソースかどうかを確認し、処理するかどうかを決めます。デフォルトではスキップしてください。- Beautiful Soupの旧バージョン使用:判定のダウングレードには親タグ名を使用できますが、バージョン4.9.0以上へのアップグレードが推奨されます。
alt、titleなどの属性を翻訳するには:別の属性トラバーサルロジックを書く必要があります。この記事の手法ではこの部分は扱っていません。
❓ よくある質問(FAQ)
1. 翻訳したいテキストを直接find_all(text=True)で取得できますか?
この方法は純粋なコンテンツ抽出に適していますが、翻訳の場面ではスクリプトやスタイルシートのような特別なサブクラスが通常のテキストとして扱われることがあり、リスクが生じます。
2.Beautiful Soup 版本较旧时怎么办?
親タグ名を劣化オプションとしてチェックできますが、明示的な型検査が常に推奨されます。バージョン4.9.0以降が推奨されます。
3. 交換後、HTMLの長さは大きく変わります。何に注意すべきでしょうか?
長さの変動が300%を超える場合は警告をマークし、注入やレイアウトオーバーフローを防ぐために、まだ脱出されていない特殊文字がないか翻訳をチェックします。
4. altやtitleのような属性値はこのコードで扱われますか?
いいえ。 この論文では属性値については扱っていません。別の属性トラバーサルロジックを書く必要があります。
5. 実際のファイルに直接使うことはできますか?
まずはオリジナルを保持し、認可されたアンミタイゼーションファイルでテストすることをお勧めします。 合成サンプルチェックに合格したコードがすべての本物ファイルを保証するわけではありません。
📝 概要
ウェブ翻訳の鍵は、まずノードタイプを特定し、それを置き換えるかどうかを決めることです。 Script、Stylesheet、Commentなどの特殊な文字列を明示的にフィルタリングし、アクセプタンス行列を使って結果を検証し、テキスト翻訳中にページが正しく動作するようにしましょう。


