Перевод файлов XLIFF с помощью BeautifulSoup

Я перевожу файл Xliff, используя пакеты BeautifulSoup и googletrans. Мне удалось извлечь все строки и перевести их, а также удалось заменить строки, создав новый тег с переводами, например.

<trans-unit id="100890::53706_004">
<source>Continue in store</source>
<target>Kontynuuj w sklepie</target>
</trans-unit>

Проблема возникает, когда в исходном теге есть другие теги внутри.

e.g.

<source><x ctype="x-htmltag" equiv-text="&lt;b&gt;" id="html_tag_191"/>Choose your product\
<x ctype="x-htmltag" equiv-text="&lt;/b&gt;" id="html_tag_192"/>From a list: </source>

У этих тегов разное количество и разный порядок появления строк. Например. <source> text1 <x /> <x/> text2 <x/> text3 </source>. Каждый тег x уникален с разными идентификаторами и атрибутами.

Есть ли способ изменить текст внутри тега без создания нового тега? Я думал, что могу извлечь теги x и их атрибуты, но порядок или строка и тег x в разных строках кода сильно различаются, я не уверен, как это сделать. Может, есть другой пакет, который лучше подходит для перевода xliff файлов?


person Julia    schedule 09.02.2021    source источник
comment
в вопросе добавить ожидаемый результат для этого <source>. С BeautifulSoup, вероятно, вам придется использовать for-loop или list(), чтобы поместить всех детей внутрь <source> и работать с ними.   -  person furas    schedule 09.02.2021
comment
Не могли бы вы отредактировать вопрос, чтобы показать, какой результат вы хотите получить для данного источника   -  person Martin Evans    schedule 09.02.2021
comment
Существует множество инструментов (в основном коммерческие, некоторые бесплатные), которые упрощают перевод XLIFF. Попробуйте поискать CAT-программы.   -  person Endre Both    schedule 10.02.2021


Ответы (3)


Вы можете использовать for-loop для работы со всеми дочерними элементами в source.
И вы можете дублировать их с copy.copy(child) и append на target.
В то же время вы можете проверить, является ли child NavigableString, и преобразовать его.


text = '''<source><x ctype="x-htmltag" equiv-text="&lt;b&gt;" id="html_tag_191"/>Choose your product\
<x ctype="x-htmltag" equiv-text="&lt;/b&gt;" id="html_tag_192"/>From a list: </source>'''

conversions = {
    'Choose your product': 'Wybierz swój produkt',
    'From a list: ': 'Z listy: ',
}

from bs4 import BeautifulSoup as BS
from bs4.element import NavigableString
import copy

#soup = BS(text, 'html.parser')  # it has problem to parse it
#soup = BS(text, 'html5lib')     # it has problem to parse it
soup = BS(text, 'lxml')

# create `<target>`
target = soup.new_tag('target')

# add `<target>` after `<source>
source = soup.find('source')
source.insert_after('', target)

# work with children in `<source>`
for child in source:
    print('type:', type(child))

    # duplicate child and add to `<target>`
    child = copy.copy(child)
    target.append(child)

    # convert text and replace in child in `<target>`        
    if isinstance(child, NavigableString):
        new_text = conversions[child.string]
        child.string.replace_with(new_text)

print('--- target ---')
print(target)
print('--- source ---')
print(source)
print('--- soup ---')
print(soup)

Результат (немного отредактирован, чтобы было удобнее читать):

type: <class 'bs4.element.Tag'>
type: <class 'bs4.element.NavigableString'>
type: <class 'bs4.element.Tag'>
type: <class 'bs4.element.NavigableString'>

--- target ---

<target>
  <x ctype="x-htmltag" equiv-text="&lt;b&gt;" id="html_tag_191"></x>
  Wybierz swój produkt
  <x ctype="x-htmltag" equiv-text="&lt;/b&gt;" id="html_tag_192"></x>
  Z listy: 
</target>

--- source ---

<source>
  <x ctype="x-htmltag" equiv-text="&lt;b&gt;" id="html_tag_191"></x>
  Choose your product
  <x ctype="x-htmltag" equiv-text="&lt;/b&gt;" id="html_tag_192"></x>
  From a list: 
</source>

--- soup ---

<html><body>
<source>
  <x ctype="x-htmltag" equiv-text="&lt;b&gt;" id="html_tag_191"></x>
  Choose your product
  <x ctype="x-htmltag" equiv-text="&lt;/b&gt;" id="html_tag_192"></x>
  From a list: 
</source>
<target>
  <x ctype="x-htmltag" equiv-text="&lt;b&gt;" id="html_tag_191"></x>
  Wybierz swój produkt
  <x ctype="x-htmltag" equiv-text="&lt;/b&gt;" id="html_tag_192"></x>
  Z listy: 
</target>
</body></html>
person furas    schedule 09.02.2021

Чтобы извлечь две текстовые записи из <source>, вы можете использовать следующий подход:

from bs4 import BeautifulSoup
import requests

html = """<source><x ctype="x-htmltag" equiv-text="&lt;b&gt;" id="html_tag_191"/>Choose your product\
<x ctype="x-htmltag" equiv-text="&lt;/b&gt;" id="html_tag_192"/>From a list: </source>"""

soup = BeautifulSoup(html, 'lxml')
print(list(soup.source.stripped_strings))

Даю вам:

['Choose your product', 'From a list:']
person Martin Evans    schedule 09.02.2021

Я бы рекомендовал не анализировать файлы XLIFF с помощью обычного анализатора XML. Вместо этого попробуйте найти специализированный инструментарий XLIFF. Есть несколько проектов на Python, но у меня нет опыта работы с ними (я: в основном, Java-парень).

person martin_wun    schedule 15.06.2021