Пытаясь сгенерировать ts-файлы с помощью PySide6-lupdate, я обнаружил следующую ситуацию:
Упрощенный код Python выглядит следующим образом.
from PySide6.QtCore import QObject
class Foo(QObject):
def info(self):
return self.tr('inside')
Bar = Foo()
Bar.tr('outside')
self = Foo()
self.tr('special one')
И это соответствующий контент в файле .ts, созданный PySide6-lupdate.
<context>
<name>Bar</name>
<message>
<location filename = "../test.py" line = "11"/>
<source>outside</source>
<translation type = "unfinished"></translation>
</message>
</context>
<context>
<name>Foo</name>
<message>
<location filename = "../test.py" line = "8"/>
<source>inside</source>
<translation type = "unfinished"></translation>
</message>
<message>
<location filename = "../test.py" line = "12"/>
<source>special one</source>
<translation type = "unfinished"></translation>
</message>
</context>
Контекст tr резюмируется следующим образом:
Foo
такой же, как имя класса.Bar
контекстом является Bar
, которое является именем переменной.self
контекст снова равен Foo
.Я хотел бы знать, в чем разница и как убедиться, что контекст метода tr является именем класса.
Вот что меня смущает. Поскольку контекст связан с классом, почему вторая строка outside
становится Bar
контекстом? @musicamante
Я не уверен, что понимаю. Ваш вопрос касается фактического результата программы (что tr()
возвращает) или результата lupdate
? Потому что если вы спрашиваете о последнем, то учтите, что он, вероятно, основан на простом анализе кода, который не всегда надежен в автоматизированных инструментах. Кроме того, по крайней мере в PyQt (но, AFAIR, это также справедливо и в PySide), обычно лучше использовать QApplication.translate()
и явно указывать контекст для каждой строки из-за того, как работает Python (который является динамическим, тогда как контексты в C++ извлекаются из-за статической компиляции).
Мой вопрос касается вывода lupdate
. Это потому, что Python динамичен и не может точно определить контекст. И решение состоит в том, чтобы предоставить явный контекст через lupdate
. Верно? @musicamante
Да. Я не могу найти подходящую документацию по PySide, но у PyQt есть объяснение по этому поводу. Я действительно не знаю, как на самом деле работает lupdate (к тому же я обычно имею дело с PyQt5), но возможно, что он просто пытается создать ts-файлы, просто основываясь на догадках, которые анализируют исходники (и поскольку синтаксический анализ не учитывает логику программы , значит, это не всегда достоверно). В любом случае, насколько мне известно, использование QApplication.translate(<context>, <text>)
обычно безопаснее, независимо от вывода ts.
Спасибо! Не могли бы вы добавить ответ ниже? Тогда я смогу принять это и закончить этот вопрос. @musicamante
Я бы предпочел этого не делать: некоторые аспекты, которые я написал выше, основаны на предположениях, я обычно не использую PySide, у меня пока мало опыта работы с Qt6, и я также знаю, что были внесены некоторые изменения, связанные с i18n. во всех трех в последнее время (Qt6, PyQt6 и PySide6), поэтому я не могу дать достоверный ответ. Я предлагаю провести самостоятельное исследование на основе того, что обсуждалось выше, и в конечном итоге опубликовать свой собственный ответ (внизу этой страницы есть специальная кнопка) после сбора достаточного количества данных, чтобы кто-нибудь еще в конечном итоге нашел более надежный ответ. на основе вашего исследования.
попробуй это
from PySide6.QtCore import QObject
class Foo(QObject):
def info(self):
return Foo.tr('inside')
Bar = Foo()
Foo.tr('outside')
self = Foo()
Foo.tr('special one')
Наконец, я нашел причину, прочитав исходный код lupdate
(ссылка). Исходный код написан на C++, и я мало о нем знаю, поэтому могу дать лишь приблизительное объяснение.
Во-первых, lupdate
не знает о среде выполнения Python. Он просто угадывает возможный контекст с помощью кода Python.
При угадывании контекста tr
сначала будет определен текущий prefix
. Например, prefix
из bar.tr
— это bar
. Затем он определяет контекст на основе prefix
следующим образом:
prefix
пусто (например, глобальная функция), контекстом является defaultContext
, который представляет собой пустой массив QByteArray, и соответствующий ему контекст в сгенерированном файле .ts также пуст.prefix
равно self
, контекст извлекается из ContextStack, который содержит имя класса.prefix
.Вернемся к ситуации в вопросе, в файле .ts:
inside
— Foo
, потому что tr
находится в классе и имеет префикс self
в коде Python.outside
— Bar
, потому что tr
имеет префикс Bar
.special one
равен Foo
, поскольку tr
имеет префикс self
, а ContextStack не обновляется вовремя (ContextStack обрабатывается, только если обнаружен class
или def
, поэтому имя класса все еще находится здесь в ContextStack)В конце концов, рекомендуемое решение — предоставить явный контекст через QApplication.translate()
.
Ваш вопрос неясен. Контекст основан на классе, а не на экземпляре, что имеет смысл: 1. имя ссылки на экземпляр не имеет значения (имя может вообще не быть, или один и тот же экземпляр может иметь несколько ссылок с разными именами) ; 2. даже если это не так, Qt не знает Python, и поэтому у него нет возможности узнать, как называется ссылка).