Непонятно, как PySide6-lupdate определяет контекст для метода tr

Пытаясь сгенерировать 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 такой же, как имя класса.
  • Для экземпляра Foo с именем переменной Bar контекстом является Bar, которое является именем переменной.
  • Точнее, для экземпляра Foo с именем переменной self контекст снова равен Foo.

Я хотел бы знать, в чем разница и как убедиться, что контекст метода tr является именем класса.

Ваш вопрос неясен. Контекст основан на классе, а не на экземпляре, что имеет смысл: 1. имя ссылки на экземпляр не имеет значения (имя может вообще не быть, или один и тот же экземпляр может иметь несколько ссылок с разными именами) ; 2. даже если это не так, Qt не знает Python, и поэтому у него нет возможности узнать, как называется ссылка).

musicamante 15.04.2024 19:05

Вот что меня смущает. Поскольку контекст связан с классом, почему вторая строка outside становится Bar контекстом? @musicamante

Djing 16.04.2024 09:23

Я не уверен, что понимаю. Ваш вопрос касается фактического результата программы (что tr() возвращает) или результата lupdate? Потому что если вы спрашиваете о последнем, то учтите, что он, вероятно, основан на простом анализе кода, который не всегда надежен в автоматизированных инструментах. Кроме того, по крайней мере в PyQt (но, AFAIR, это также справедливо и в PySide), обычно лучше использовать QApplication.translate() и явно указывать контекст для каждой строки из-за того, как работает Python (который является динамическим, тогда как контексты в C++ извлекаются из-за статической компиляции).

musicamante 16.04.2024 19:59

Мой вопрос касается вывода lupdate. Это потому, что Python динамичен и не может точно определить контекст. И решение состоит в том, чтобы предоставить явный контекст через lupdate. Верно? @musicamante

Djing 17.04.2024 03:05

Да. Я не могу найти подходящую документацию по PySide, но у PyQt есть объяснение по этому поводу. Я действительно не знаю, как на самом деле работает lupdate (к тому же я обычно имею дело с PyQt5), но возможно, что он просто пытается создать ts-файлы, просто основываясь на догадках, которые анализируют исходники (и поскольку синтаксический анализ не учитывает логику программы , значит, это не всегда достоверно). В любом случае, насколько мне известно, использование QApplication.translate(<context>, <text>) обычно безопаснее, независимо от вывода ts.

musicamante 17.04.2024 03:17

Спасибо! Не могли бы вы добавить ответ ниже? Тогда я смогу принять это и закончить этот вопрос. @musicamante

Djing 17.04.2024 03:39

Я бы предпочел этого не делать: некоторые аспекты, которые я написал выше, основаны на предположениях, я обычно не использую PySide, у меня пока мало опыта работы с Qt6, и я также знаю, что были внесены некоторые изменения, связанные с i18n. во всех трех в последнее время (Qt6, PyQt6 и PySide6), поэтому я не могу дать достоверный ответ. Я предлагаю провести самостоятельное исследование на основе того, что обсуждалось выше, и в конечном итоге опубликовать свой собственный ответ (внизу этой страницы есть специальная кнопка) после сбора достаточного количества данных, чтобы кто-нибудь еще в конечном итоге нашел более надежный ответ. на основе вашего исследования.

musicamante 17.04.2024 03:55
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
7
67
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

попробуй это

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 следующим образом:

  1. Если prefix пусто (например, глобальная функция), контекстом является defaultContext, который представляет собой пустой массив QByteArray, и соответствующий ему контекст в сгенерированном файле .ts также пуст.
  2. Если prefix равно ​​self, контекст извлекается из ContextStack, который содержит имя класса.
  3. В других случаях контекстом является prefix.

Вернемся к ситуации в вопросе, в файле .ts:

  1. Контекст строки insideFoo, потому что tr находится в классе и имеет префикс self в коде Python.
  2. Контекст строки outsideBar, потому что tr имеет префикс Bar.
  3. В частности, контекст строки special one равен Foo, поскольку tr имеет префикс self, а ContextStack не обновляется вовремя (ContextStack обрабатывается, только если обнаружен class или def, поэтому имя класса все еще находится здесь в ContextStack)

В конце концов, рекомендуемое решение — предоставить явный контекст через QApplication.translate().

Другие вопросы по теме