Translating an external workbench/pl: Difference between revisions

From FreeCAD Documentation
No edit summary
No edit summary
 
(44 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<languages/>
<languages/>


W poniższych uwagach, {{incode|" kontekst"}} powinien być nazwą twojego dodatku lub środowiska pracy, na przykład, {{incode|"MySuperAddon"}} lub {{incode|"DraftPlus"}}, lub cokolwiek innego. Ten kontekst sprawia, że wszystkie tłumaczenia twojego kodu będą zebrane pod tą samą nazwą, aby tłumacze mogli je łatwiej zidentyfikować. Oznacza to, że będą oni dokładnie wiedzieli, do którego dodatku lub środowiska pracy należy dany ciąg znaków.
W poniższych uwagach, {{incode|" kontekst"}} powinien być nazwą twojego dodatku lub środowiska pracy, na przykład, {{incode|"MySuperAddon"}} lub {{incode|"DraftPlus"}}, lub cokolwiek innego. Wielkość liter ma tu znaczenie: na przykład {{incode|"Context"}} to nie to samo co {{incode|"context"}}. Ten kontekst sprawia, że wszystkie tłumaczenia twojego kodu będą zebrane pod tą samą nazwą, aby tłumacze mogli je łatwiej zidentyfikować. Oznacza to, że będą oni dokładnie wiedzieli, do którego dodatku lub środowiska pracy należy dany ciąg znaków.


'''Uwaga''': Oto skrypt all-in-one, który automatyzuje całą procedurę opisaną poniżej ''(zalecamy jednak przeczytanie procedury, aby wiedzieć, co skrypt powinien zrobić)'': https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py
'''Uwaga''': Oto skrypt all-in-one, który automatyzuje całą procedurę opisaną poniżej ''(zalecamy jednak przeczytanie procedury, aby wiedzieć, co skrypt powinien zrobić)'': https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py


<span id="Preparing_the_sources"></span>
==Przygotowywanie źródeł==
==Przygotowywanie źródeł==


<span id="General"></span>
===Informacje ogólne===
===Informacje ogólne===


Line 13: Line 15:
* Tekst, który jest wyświetlany w {{incode|FreeCAD.Console}}, jest wyświetlany w oknie "Widok raportu" i dlatego powinien zostać przetłumaczony. Okno "Widok raportu" jest czymś innym niż konsola Python.
* Tekst, który jest wyświetlany w {{incode|FreeCAD.Console}}, jest wyświetlany w oknie "Widok raportu" i dlatego powinien zostać przetłumaczony. Okno "Widok raportu" jest czymś innym niż konsola Python.


<span id="In_every_Python_.py_file"></span>
===W każdym pliku .py Python===
===W każdym pliku .py Python===


* W każdym pliku, w którym trzeba przetłumaczyć tekst, należy zdefiniować funkcję {{incode|translate()}}. Możesz użyć w pełni kwalifikowanej nazwy z Qt, ale to jest trochę bardziej przejrzyste w użyciu:
* W każdym pliku, w którym trzeba przetłumaczyć tekst, należy zdefiniować funkcję {{incode|translate()}}. Musi to być dokładnie nazwa {{incode|translate}}: ekstraktor ciągów znaków opiera się właśnie na tej nazwie. Możesz użyć w pełni kwalifikowanej nazwy z Qt, ale to jest trochę bardziej przejrzyste w użyciu:


: {{Code|code=
: {{Code|code=
Line 49: Line 52:
}}
}}


<div class="mw-translate-fuzzy">
Może to być użyte wszędzie: w {{incode|print()}}, w {{incode|FreeCAD.Console.PrintMessage()}}, w oknach dialogowych Qt, itd. Funkcje {{incode|FreeCAD.Console}} nie dodają automatycznie znaku nowej linii ''({{incode|\n}})'', więc musi on być dodany na końcu, jeśli jest to pożądane. Ten znak również nie wymaga tłumaczenia, więc może znajdować się poza funkcją tłumaczącą:
Może to być użyte wszędzie: w {{incode|print()}}, w {{incode|FreeCAD.Console.PrintMessage()}}, w oknach dialogowych Qt, itd. Funkcje {{incode|FreeCAD.Console}} nie dodają automatycznie znaku nowej linii ''({{incode|\n}})'', więc musi on być dodany na końcu, jeśli jest to pożądane. Ten znak również nie wymaga tłumaczenia, więc może znajdować się poza funkcją tłumaczącą:

{{Code|code=
: {{Code|code=
FreeCAD.Console.PrintMessage(translate("context", "My text") + "\n")
FreeCAD.Console.PrintMessage(translate("context", "My text") + "\n")
}}
}}

* Jeśli używasz plików {{incode|.ui}} wykonanych za pomocą QtDesigner, nie trzeba z nimi robić nic specjalnego.
* Jeśli używasz plików {{incode|.ui}} wykonanych za pomocą QtDesigner, nie trzeba z nimi robić nic specjalnego.
* Podczas tworzenia nowych obiektów, nie tłumacz "Nazwy" obiektu. Należy raczej tłumaczyć "Etykietę" obiektu. Różnica polega na tym, że "Nazwa" jest unikalna; pozostaje taka sama przez całe życie obiektu; z drugiej strony, "Etykieta" może być zmieniana przez użytkownika wedle życzenia.
* Podczas tworzenia nowych obiektów, nie tłumacz "Nazwy" obiektu. Należy raczej tłumaczyć "Etykietę" obiektu. Różnica polega na tym, że "Nazwa" jest unikalna; pozostaje taka sama przez całe życie obiektu; z drugiej strony, "Etykieta" może być zmieniana przez użytkownika wedle życzenia.
* Kiedy tworzysz właściwości dla swoich obiektów, nie tłumacz nazwy właściwości. Ale umieść opis wewnątrz {{incode|QT_TRANSLATE_NOOP}}:
* Kiedy tworzysz właściwości dla swoich obiektów, nie tłumacz nazwy właściwości. Ale umieść opis wewnątrz {{incode|QT_TRANSLATE_NOOP}}:
{{Code|code=
obj.addProperty("App::PropertyBool", "MyProperty", "PropertyGroup", QT_TRANSLATE_NOOP("App::Property", "This is what My Property does"))
}}
Nie używaj swojego własnego {{incode|"kontekstu"}} w tym konkretnym przypadku. Zachowaj {{incode|"App::Property"}}.
* Nie tłumacz tekstu operacji na dokumentach wykonanych za pomocą {{incode|Document.openTransaction()}}
</div>

: {{Code|code=
FreeCAD.Console.PrintMessage(translate("context", "My text") + "\n")
}}

* If you are using {{incode|.ui}} files made with QtDesigner, nothing special needs to be done with them.
* When creating new objects, do not translate the object's "Name". Rather, translate the object's "Label". The difference is that a "Name" is unique; it stays the same throughout the life of the object; on the other hand, a "Label" can be changed by the user as desired.
* When creating properties for your objects, don't translate the property name. But place the description inside {{incode|QT_TRANSLATE_NOOP}}:


: {{Code|code=
: {{Code|code=
Line 76: Line 67:
}}
}}


: Don't use your own {{incode|"context"}} in this specific case. Keep {{incode|"App::Property"}}.
Nie używaj swojego własnego {{incode|"kontekstu"}} w tym konkretnym przypadku. Zachowaj {{incode|"App::Property"}}.

* Do not translate the text of document transactions made with {{incode|Document.openTransaction()}}


<span id="In_InitGui.py"></span>
===Wewnątrz InitGui.py===
===Wewnątrz InitGui.py===


* Dodaj następującą linię, na początku pliku:
<div class="mw-translate-fuzzy">
* Dodaj następującą linię, blisko początku pliku:
{{Code|code=
def QT_TRANSLATE_NOOP(scope, text):
return text
}}
* Aby przetłumaczyć nazwy menu:
{{Code|code=
self.appendMenu(QT_TRANSLATE_NOOP("context", "My menu"), [list of commands, ...])
}}
* Makro {{incode|QT_TRANSLATE_NOOP}} nie robi nic, ale zaznacza teksty, które później zostaną pobrane przez narzędzie {{incode|lupdate}}. Ponieważ nie robi ono w zasadzie nic, używamy go tylko w szczególnych przypadkach, gdy FreeCAD sam się wszystkim zajmuje.
* Dodaj ścieżkę do folderu {{incode|translations/}} w funkcji Initialized:
{{Code|code=
FreeCADGui.addLanguagePath("/path/to/translations")
}}
Plik {{incode|InitGui.py}} nie ma atrybutu '''plik''', więc nie jest łatwo znaleźć względną lokalizację folderu tłumaczeń. Łatwym sposobem na obejście tego problemu jest zaimportowanie innego pliku z tego samego folderu, a następnie wykonanie w tym pliku polecenia
{{Code|code=
FreeCADGui.addLanguagePath(os.path.join(os.path.dirname(__file__), "translations"))
}}
</div>


: {{Code|code=
: {{Code|code=
def QT_TRANSLATE_NOOP(scope, text):
def QT_TRANSLATE_NOOP(context, text):
return text
return text
}}
}}


* Makro {{incode|QT_TRANSLATE_NOOP}} nie robi nic, ale zaznacza teksty, które później zostaną pobrane przez narzędzie {{incode|lupdate}}. Ponieważ nie robi ono w zasadzie nic, używamy go tylko w szczególnych przypadkach, gdy FreeCAD sam się wszystkim zajmuje.
* To translate menu names:

* Aby przetłumaczyć nazwy menu i pasków narzędzi, użyj słowa {{incode|"Workbench"}} jako kontekstu:


: {{Code|code=
: {{Code|code=
self.appendMenu(QT_TRANSLATE_NOOP("context", "My menu"), [list of commands, ...])
self.appendMenu(QT_TRANSLATE_NOOP("Workbench", "My menu"), [list of commands, ...])
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "My toolbar"), [list of commands, ...])
}}
}}


* Dodaj ścieżkę do katalogu {{incode|translations/}} i zaktualizuj ustawienia regionalne w funkcji ''Initialized'':
* The {{incode|QT_TRANSLATE_NOOP}} macro doesn't do anything, but it marks texts to be picked up by the {{incode|lupdate}} utility later on. Since it doesn't actually do anything, we only use it in special cases where FreeCAD itself takes care of everything.
* Add the path to your {{incode|translations/}} folder in the Initialized function:


: {{Code|code=
: {{Code|code=
FreeCADGui.addLanguagePath("/path/to/translations")
FreeCADGui.addLanguagePath("/path/to/translations")
FreeCADGui.updateLocale()
}}
}}


Plik {{incode|InitGui.py}} nie ma atrybutu '''plik''', więc nie jest łatwo znaleźć względną lokalizację folderu tłumaczeń. Łatwym sposobem na obejście tego problemu jest zaimportowanie innego pliku z tego samego folderu, a następnie wykonanie w tym pliku polecenia:
: The {{incode|InitGui.py}} file has no '''file''' attribute, so it is not easy to find the translations folder's relative location. An easy way to work around this is to make it import another file from the same folder, and in that file do:


: {{Code|code=
: {{Code|code=
FreeCADGui.addLanguagePath(os.path.join(os.path.dirname(__file__), "translations"))
FreeCADGui.addLanguagePath(os.path.join(os.path.dirname(__file__), "translations"))
FreeCADGui.updateLocale()
}}
}}


<span id="Inside_each_FreeCAD_command_class"></span>
===Wewnątrz każdej klasy poleceń FreeCAD===
===Wewnątrz każdej klasy poleceń FreeCAD===


<div class="mw-translate-fuzzy">
* Dodaj następującą linię, na początku pliku:
* Dodaj następującą linię, na początku pliku:
{{Code|code=
def QT_TRANSLATE_NOOP(context, text):
return text
}}
* Przetłumacz {{incode|'MenuText'}} i {{incode|'Tooltip'}} polecenia w ten sposób:
</div>


: {{Code|code=
: {{Code|code=
Line 143: Line 112:
}}
}}


* Translate the {{incode|'MenuText'}} and {{incode|'Tooltip'}} of the command like this:
* Przetłumacz {{incode|'MenuText'}} i {{incode|'Tooltip'}} polecenia w ten sposób:


: {{Code|code=
: {{Code|code=
Line 154: Line 123:
}}
}}


gdzie {{incode|"CommandName"}} jest nazwą polecenia, zdefiniowaną przez:
<div class="mw-translate-fuzzy">
gdzie {{incode|"CommandName"}} jest nazwą polecenia, zdefiniowaną przez
{{Code|code=
FreeCADGui.addCommand('CommandName', My_Command_Class())
}}
</div>


: {{Code|code=
: {{Code|code=
Line 165: Line 129:
}}
}}


<span id="Gather_all_the_strings_from_your_module"></span>
==Zbierz wszystkie ciągi z twojego modułu==
==Zbierz wszystkie ciągi z twojego modułu==


* Będziesz potrzebował zainstalowanych w systemie narzędzi {{incode|lupdate}}, {{incode|lconvert}}, {{incode|lrelease}} i {{incode|pylupdate}}. W dystrybucjach Linuksa są one zwykle dostępne w pakietach o nazwach {{incode|pyside-tools}} lub {{incode|pyside2-tools}}. W niektórych systemach {{incode|lupdate}} nazywa się {{incode|lupdate4}} lub {{incode|lupdate5}} lub {{incode|lupdate-qt4}} lub podobnie. To samo dotyczy innych narzędzi. Możesz użyć wersji Qt4 lub Qt5 według własnego uznania. W Qt6 nie ma oddzielnego systemu tłumaczeń dla plików środowiska Python, {{incode|lupdate}} jest używany do wyodrębniania łańcuchów ze wszystkich typów plików źródłowych.
<div class="mw-translate-fuzzy">
* Będziesz potrzebował zainstalowanych w systemie narzędzi {{incode|lupdate}}, {{incode|lconvert}}, {{incode|lrelease}} i {{incode|pylupdate}}. W dystrybucjach Linuksa są one zwykle dostępne w pakietach o nazwach {{incode|pyside-tools}} lub {{incode|pyside2-tools}}. W niektórych systemach {{incode|lupdate}} nazywa się {{incode|lupdate4}} lub {{incode|lupdate5}} lub {{incode|lupdate-qt4}} lub podobnie. To samo dotyczy innych narzędzi. Możesz użyć wersji Qt4 lub Qt5 według własnego uznania.
* Jeśli masz pliki {{incode|.ui}}, musisz najpierw uruchomić {{incode|lupdate}}:
* Jeśli masz pliki {{incode|.ui}}, musisz najpierw uruchomić {{incode|lupdate}}:
{{Code|code=
lupdate *.ui -ts translations/uifiles.ts
}}
To działa rekurencyjnie i znajdzie pliki {{incode|.ui}} wewnątrz wszystkich twoich katalogów.
* Jeśli masz pliki {{incode|.py}}, musisz również uruchomić {{incode|pylupdate}}:
{{Code|code=
pylupdate *.py -ts translations/pyfiles.ts
}}
* Jeśli wykonałeś obie operacje, musisz teraz połączyć te dwa pliki w jeden:
{{Code|code=
lconvert -i translations/uifiles.ts translations/pyfiles.ts -o translations/MyModule.ts
}}
* Sprawdź zawartość trzech plików {{incode|.ts}}, aby upewnić się, że zawierają one łańcuchy znaków, a następnie możesz usunąć zarówno {{incode|pyfiles.ts}}, jak i {{incode|uifiles.ts}}.
* Możesz to wszystko zrobić w jednym skrypcie bash, tak jak poniżej:
</div>


: {{Code|code=
: {{Code|code=
Line 190: Line 139:
}}
}}


: This is recursive and will find {{incode|.ui}} files inside your whole directory structure.
To działa rekurencyjnie i znajdzie pliki {{incode|.ui}} wewnątrz wszystkich twoich katalogów.


* If you have {{incode|.py}} files, you need to run {{incode|pylupdate}} too:
* Jeśli masz pliki {{incode|.py}}, musisz również uruchomić {{incode|pylupdate}}:


: {{Code|code=
: {{Code|code=
Line 198: Line 147:
}}
}}


* Jeśli wykonałeś obie operacje, musisz teraz połączyć te dwa pliki w jeden:
* If you ran both operations, you now need to unify these two files into one:


: {{Code|code=
: {{Code|code=
Line 204: Line 153:
}}
}}


* Check the contents of the three {{incode|.ts}} files to make sure that they contain the strings, then you can delete both {{incode|pyfiles.ts}} and {{incode|uifiles.ts}}.
* Sprawdź zawartość trzech plików {{incode|.ts}}, aby upewnić się, że zawierają one łańcuchy znaków, a następnie możesz usunąć zarówno {{incode|pyfiles.ts}}, jak i {{incode|uifiles.ts}}.
* You can do it all in one bash script like this:
* Możesz to wszystko zrobić w jednym skrypcie bash, tak jak poniżej:


: {{Code|code=
: {{Code|code=
Line 216: Line 165:
}}
}}


<span id="Send_the_.ts_file_to_a_translation_platform"></span>
==Przesłanie pliku .ts do platformy tłumaczeniowej==
==Przesłanie pliku .ts do platformy tłumaczeniowej==


Line 224: Line 174:
{{Emphasis|Uwaga:}} niektóre platformy, takie jak Crowdin, mogą zintegrować się z GitHubem i wykonać wszystkie procesy z punktów 2, 3 i 4 automatycznie. W tym celu nie można korzystać z konta FreeCAD Crowdin. Będziesz musiał założyć własne konto.
{{Emphasis|Uwaga:}} niektóre platformy, takie jak Crowdin, mogą zintegrować się z GitHubem i wykonać wszystkie procesy z punktów 2, 3 i 4 automatycznie. W tym celu nie można korzystać z konta FreeCAD Crowdin. Będziesz musiał założyć własne konto.


<span id="Merge_the_translations"></span>
==Scalanie tłumaczeń==
==Scalanie tłumaczeń==


Line 231: Line 182:
* Umieść wszystkie przetłumaczone pliki {{incode|.ts}}, razem ze swoim podstawowym plikiem {{incode|.ts}}, w folderze {{incode|translations/}}.
* Umieść wszystkie przetłumaczone pliki {{incode|.ts}}, razem ze swoim podstawowym plikiem {{incode|.ts}}, w folderze {{incode|translations/}}.


<span id="Compile_the_translations"></span>
==Kompilacja tłumaczeń==
==Kompilacja tłumaczeń==


Line 241: Line 193:
}}
}}


Możesz zautomatyzować ten proces:
<div class="mw-translate-fuzzy">
Możesz zautomatyzować ten proces
</div>


{{Code|code=
{{Code|code=
Line 256: Line 206:
To wszystko, czego potrzebujesz. Zauważ, że niektóre części Twojego środowiska pracy nie mogą być tłumaczone w locie, jeśli zdecydujesz się na zmianę języka. Jeśli tak jest, będziesz musiał ponownie uruchomić FreeCAD, aby nowy język został zastosowany.
To wszystko, czego potrzebujesz. Zauważ, że niektóre części Twojego środowiska pracy nie mogą być tłumaczone w locie, jeśli zdecydujesz się na zmianę języka. Jeśli tak jest, będziesz musiał ponownie uruchomić FreeCAD, aby nowy język został zastosowany.


<span id="Testing_translations"></span>
==Testowanie tłumaczeń==
==Testowanie tłumaczeń==


<div class="mw-translate-fuzzy">
# Przełącz FreeCAD na język, który przetłumaczyłeś ''(np. niemiecki)''
# Przełącz FreeCAD na język, który przetłumaczyłeś ''(np. niemiecki)''
# Załaduj tłumaczenie do FreeCAD, np. {{incode|FreeCADGui.addTranslationPath("/path/to/the/folder/containing/qmfile")}}
# Załaduj tłumaczenie do FreeCAD, np. {{incode|FreeCADGui.addTranslationPath("/path/to/the/folder/containing/qmfile")}}
# Przetestuj coś, np. {{incode|FreeCAD.Qt.translate("twój kontekst", "jakiś ciąg znaków")}}
# Przetestuj coś, np. {{incode|FreeCAD.Qt.translate("twój kontekst", "jakiś ciąg znaków")}}
</div>


<div class="mw-translate-fuzzy">
Wynik: To powinno dać ci niemieckie tłumaczenie. Jeśli to działa dobrze, to znaczy, że podstawowa konfiguracja jest w porządku. Wtedy możemy przyjrzeć się czemuś innemu. Na przykład, nazwy poleceń powinny zawsze używać specjalnego kontekstu, który jest nazwą polecenia zarejestrowanego we FreeCAD.
Wynik: To powinno dać ci niemieckie tłumaczenie. Jeśli to działa dobrze, to znaczy, że podstawowa konfiguracja jest w porządku. Wtedy możemy przyjrzeć się czemuś innemu. Na przykład, nazwy poleceń powinny zawsze używać specjalnego kontekstu, który jest nazwą polecenia zarejestrowanego we FreeCAD.
</div>


<span id="Important_notes"></span>
===Istotne uwagi===
===Istotne uwagi===


* Upewnij się, że używasz *kontekstu* i *ciągu znaków*, które rzeczywiście znajdują się w pliku ts/qm.
* Upewnij się, że używasz *kontekstu* i *ciągu znaków*, które rzeczywiście znajdują się w pliku ts/qm.


<span id="Convenience_script"></span>
==Wygodniejszy skrypt==
==Wygodniejszy skrypt==


Line 279: Line 228:
https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py
https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py


<span id="Technical_details_and_advanced_usage"></span>
== Technical details and advanced usage ==
==Szczegóły techniczne i obsługa zaawansowana==


In the above examples there are two separate functions being used: {{incode|translate()}} and {{incode|QT_TRANSLATE_NOOP}}. You may also run across {{incode|tr()}} and {{incode|QT_TR_NOOP}}, which automatically provide the "context" argument based on their calling location. These two pairs of functions are fundamentally different.
W powyższych przykładach używane dwie oddzielne funkcje: {{incode|translate()}} i {{incode|QT_TRANSLATE_NOOP}}. Możesz również natknąć się na {{incode|tr()}} i {{incode|QT_TR_NOOP}}, które automatycznie podają argument "kontekst" na podstawie miejsca wywołania. Te dwie pary funkcji zasadniczo różne.


{{incode|translate()}} and {{incode|tr()}} accomplish two separate tasks: at runtime they perform the actual translation from the string passed into them to the final translated string. This is true whether they are provided a literal string, or a variable, or a constant: the lookup is dynamic and real-time during the run of the code. However, they provide an additional non-runtime function: they are recognized by the {{incode|pylupdate}} utility. If (and only if) they contain a string literal, that literal is extracted by the utility. ONLY string literals are extracted by {{incode|pylupdate}} -- if a variable is passed it is ignored by the {{incode|pylupdate}} utility. Qt will attempt to provide a translation at runtime, but this will only work if some other piece of code called one of the translation functions with the literal string that needs to be translated, so that {{incode|pylupdate}} can extract it. Note that the code with the string literal need not actually ever execute, it must simply exist as a line of code in a file somewhere: {{incode|pylupdate}} performs no analysis or code execution, it is simply performing a string search and extraction.
{{incode|translate()}} i {{incode|tr()}} wykonują dwa oddzielne zadania: w czasie działania wykonują rzeczywiste tłumaczenie z przekazanego im łańcucha na końcowy przetłumaczony łańcuch. Jest to prawda niezależnie od tego, czy podano im łańcuch literalny, zmienną czy stałą: wyszukiwanie odbywa się dynamicznie i w czasie rzeczywistym podczas wykonywania kodu. Jednakże, zapewniają one dodatkową funkcję nie związaną z czasem rzeczywistym: rozpoznawane przez narzędzie {{incode|pylupdate}}. Jeśli (i tylko jeśli) zawierają literał łańcuchowy, to jest on wyodrębniany przez narzędzie. TYLKO literały łańcuchowe wyodrębniane przez {{incode|pylupdate}}. -- jeśli zostanie przekazana zmienna, to jest ona ignorowana przez narzędzie {{incode|pylupdate}}. Qt będzie próbowało zapewnić tłumaczenie w czasie wykonywania, ale będzie to działać tylko wtedy, gdy jakiś inny fragment kodu wywoła jedną z funkcji tłumaczących z łańcuchem, który ma być przetłumaczony, tak aby {{incode|pylupdate}} mógł go wydobyć. Zauważ, że kod z łańcuchem literalnym nie musi być w rzeczywistości wykonywany, musi po prostu istnieć jako linia kodu gdzieś w pliku: {{incode|pylupdate}} nie wykonuje żadnej analizy ani egzekucji kodu, po prostu wykonuje wyszukiwanie i ekstrakcję łańcucha.


In contrast, {{incode|QT_TRANSLATE_NOOP}} and {{incode|QT_TR_NOOP}} do nothing at all at runtime: they are literal "no-ops", and are completely ignored by running code. Their only use is to mark a literal string for extraction by {{incode|pylupdate}}: it never makes sense to place a variable within a call to one of these functions, it will have no effect. They are used in circumstances where {{incode|translate()}} or {{incode|tr()}} will be called with a variable containing the text to translate. For example, any code that is used to create a Command or a Property will use a NOOP-type function around the command menu text or tooltip, or the property docstring: at runtime when FreeCAD displays these items to the user it calls {{incode|translate()}}: the literal strings must have been extracted by {{incode|pylupdate}} at the point of creation, for example:
W przeciwieństwie do nich, {{incode|QT_TRANSLATE_NOOP}} i {{incode|QT_TR_NOOP}} nie robią nic w czasie wykonywania: dosłownymi "no-ops" i całkowicie ignorowane przez działający kod. Ich jedynym zastosowaniem jest oznaczenie dosłownego łańcucha do ekstrakcji przez {{incode|pylupdate}}: nigdy nie ma sensu umieszczać zmiennej wewnątrz wywołania jednej z tych funkcji, nie będzie to miało żadnego efektu. Używa się ich w sytuacjach, gdy {{incode|translate()}} lub {{incode|tr()}} zostaną wywołane ze zmienną zawierającą tekst do przetłumaczenia. Na przykład, każdy kod, który jest używany do tworzenia poleceń lub właściwości, użyje funkcji typu NOOP wokół tekstu menu poleceń lub etykiety narzędzia, lub docstring właściwości: w czasie działania, gdy FreeCAD wyświetla te elementy użytkownikowi, wywołuje {{incode|translate()}}: dosłowne ciągi muszą być wyodrębnione przez {{incode|pylupdate}} w punkcie tworzenia, na przykład:


{{Code|code=
{{Code|code=
Line 296: Line 246:
}}
}}


W tym zastosowaniu słownik zwracany przez tę funkcję jest dosłownie w czasie pracy:
In this usage, at runtime the dictionary returned by this function is literally:


{{Code|code=
{{Code|code=
Line 307: Line 257:
}}
}}


Nie ma odniesienia do żadnego typu informacji o tłumaczeniu. Kiedy FreeCAD faktycznie wyświetla te informacje użytkownikowi, pseudokod wygląda następująco:
There is no reference to any type of translation information. When FreeCAD actually displays this information to the user, the pseudo-code is:


{{Code|code=
{{Code|code=
Line 315: Line 265:
}}
}}


In this case, {{incode|lupdate}} cannot extract any string from the call to {{incode|translate()}} because it refers to a variable. So {{incode|lupdate}} ignores that call, but at runtime Qt searches for the string that's passed to it. As long as someplace in the code there is a call to one of the translation functions with a matching literal string (in this case, in the {{incode|GetResources()}} function), this translation call will succeed.
W tym przypadku, {{incode|lupdate}} nie może wydobyć żadnego łańcucha z wywołania {{incode|translate()}}, ponieważ odwołuje się ono do zmiennej. Zatem {{incode|lupdate}} ignoruje to wywołanie, ale w czasie wykonywania Qt szuka łańcucha, który został mu przekazany. Tak długo, jak gdzieś w kodzie znajduje się wywołanie jednej z funkcji tłumaczących z pasującym dosłownym łańcuchem (w tym przypadku w funkcji {{incode|GetResources()}}), to wywołanie tłumaczenia powiedzie się.


To verify that the expected strings are being extracted, you can manually run the {{incode|pylupdate}} command:
Aby sprawdzić, czy wyodrębniane oczekiwane ciągi znaków, możesz ręcznie uruchomić polecenie {{incode|pylupdate}}:


{{Code|code=
{{Code|code=
Line 323: Line 273:
}}
}}


The file {{incode|outfile.ts}} will contain the set of strings that are uploaded to CrowdIn for translation.
Plik {{incode|outfile.ts}} będzie zawierał zestaw ciągów znaków, które przesyłane do CrowdIn w celu przetłumaczenia.


<span id="Important_references"></span>
==Ważne odnośniki==
==Ważne odnośniki==


* Dlaczego warto i jak tłumaczyć funkcje {{incode|openCommand()}} ''([https://forum.freecadweb.org/viewtopic.php?f=10&t=55869 forum thread])''.
* Dlaczego warto i jak tłumaczyć funkcje {{incode|openCommand()}} ''([https://forum.freecadweb.org/viewtopic.php?f=10&t=55869 forum thread])''.


<span id="Related_Pages"></span>
== Related Pages ==
==Powiązane strony==


<div class="mw-translate-fuzzy">
==Strony pokrewne==
* [[External_workbenches/pl|Zewnętrzne środowiska pracy]]
* [[External_workbenches/pl|Zewnętrzne środowiska pracy]]
* [[Localisation/pl|Lokalizacja - tłumaczenie interfejsu i dokumentacji]]
* [[Localisation/pl|Lokalizacja - tłumaczenie interfejsu i dokumentacji]]
* Aby uzyskać więcej informacji, złóż zapytanie tutaj [https://forum.freecadweb.org/viewtopic.php?f=10&t=36413 Tłumaczenie zewnętrznych środowisk pracy].
* Aby uzyskać więcej informacji, złóż zapytanie tutaj [https://forum.freecadweb.org/viewtopic.php?f=10&t=36413 Tłumaczenie zewnętrznych środowisk pracy].
</div>





Latest revision as of 12:08, 1 March 2024

W poniższych uwagach, " kontekst" powinien być nazwą twojego dodatku lub środowiska pracy, na przykład, "MySuperAddon" lub "DraftPlus", lub cokolwiek innego. Wielkość liter ma tu znaczenie: na przykład "Context" to nie to samo co "context". Ten kontekst sprawia, że wszystkie tłumaczenia twojego kodu będą zebrane pod tą samą nazwą, aby tłumacze mogli je łatwiej zidentyfikować. Oznacza to, że będą oni dokładnie wiedzieli, do którego dodatku lub środowiska pracy należy dany ciąg znaków.

Uwaga: Oto skrypt all-in-one, który automatyzuje całą procedurę opisaną poniżej (zalecamy jednak przeczytanie procedury, aby wiedzieć, co skrypt powinien zrobić): https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py

Przygotowywanie źródeł

Informacje ogólne

  • Dodaj folder translations/. Możesz nadać mu inną nazwę, ale tak będzie łatwiej, ponieważ jest on taki sam w całym FreeCAD. W tym folderze umieścisz pliki .ts (pliki tłumaczenia "źródła") i .qm (skompilowane pliki tłumaczenia).
  • Należy tłumaczyć tylko tekst, który jest wyświetlany użytkownikowi w interfejsie użytkownika programu FreeCAD. Tekst, wyświetlany w konsoli Python nie powinien być tłumaczony.
  • Tekst, który jest wyświetlany w FreeCAD.Console, jest wyświetlany w oknie "Widok raportu" i dlatego powinien zostać przetłumaczony. Okno "Widok raportu" jest czymś innym niż konsola Python.

W każdym pliku .py Python

  • W każdym pliku, w którym trzeba przetłumaczyć tekst, należy zdefiniować funkcję translate(). Musi to być dokładnie nazwa translate: ekstraktor ciągów znaków opiera się właśnie na tej nazwie. Możesz użyć w pełni kwalifikowanej nazwy z Qt, ale to jest trochę bardziej przejrzyste w użyciu:
import FreeCAD
translate = FreeCAD.Qt.translate
  • Cały tekst, który musi zostać przetłumaczony, musi zostać przekazany przez funkcję translate():
print("My text")
staje się:
print(translate("context", "My text"))
Pamiętaj, że translate() nie jest zwykłą funkcją: służy również jako "tag" dla narzędzia do przetwarzania tekstu lupdate, więc musi mieć nazwę dokładnie "translate". Program lupdate jest prostym procesorem tekstu, nie wykonuje Twojego kodu. Do funkcji translate() musisz przekazywać bezpośrednio literały łańcuchowe: nie możesz przekazywać zmiennych, stałych, itp. Na przykład:
# This works:
FreeCAD.Console.PrintMessage(translate("context", "My text") + "\n")

# This does not, lupdate only sees the word "a_variable", and doesn't know what that is:
a_variable = "My text"
FreeCAD.Console.PrintMessage(translate("context", a_variable ) + "\n")

# But this works -- a_variable will contain the translated string:
a_variable = translate("context", "My text")
FreeCAD.Console.PrintMessage(a_variable  + "\n")

Może to być użyte wszędzie: w print(), w FreeCAD.Console.PrintMessage(), w oknach dialogowych Qt, itd. Funkcje FreeCAD.Console nie dodają automatycznie znaku nowej linii (\n), więc musi on być dodany na końcu, jeśli jest to pożądane. Ten znak również nie wymaga tłumaczenia, więc może znajdować się poza funkcją tłumaczącą:

FreeCAD.Console.PrintMessage(translate("context", "My text") + "\n")


  • Jeśli używasz plików .ui wykonanych za pomocą QtDesigner, nie trzeba z nimi robić nic specjalnego.
  • Podczas tworzenia nowych obiektów, nie tłumacz "Nazwy" obiektu. Należy raczej tłumaczyć "Etykietę" obiektu. Różnica polega na tym, że "Nazwa" jest unikalna; pozostaje taka sama przez całe życie obiektu; z drugiej strony, "Etykieta" może być zmieniana przez użytkownika wedle życzenia.
  • Kiedy tworzysz właściwości dla swoich obiektów, nie tłumacz nazwy właściwości. Ale umieść opis wewnątrz QT_TRANSLATE_NOOP:
obj.addProperty("App::PropertyBool", "MyProperty", "PropertyGroup", QT_TRANSLATE_NOOP("App::Property", "This is what My Property does"))

Nie używaj swojego własnego "kontekstu" w tym konkretnym przypadku. Zachowaj "App::Property".

Wewnątrz InitGui.py

  • Dodaj następującą linię, na początku pliku:
def QT_TRANSLATE_NOOP(context, text):
    return text
  • Makro QT_TRANSLATE_NOOP nie robi nic, ale zaznacza teksty, które później zostaną pobrane przez narzędzie lupdate. Ponieważ nie robi ono w zasadzie nic, używamy go tylko w szczególnych przypadkach, gdy FreeCAD sam się wszystkim zajmuje.
  • Aby przetłumaczyć nazwy menu i pasków narzędzi, użyj słowa "Workbench" jako kontekstu:
self.appendMenu(QT_TRANSLATE_NOOP("Workbench", "My menu"), [list of commands, ...])
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "My toolbar"), [list of commands, ...])
  • Dodaj ścieżkę do katalogu translations/ i zaktualizuj ustawienia regionalne w funkcji Initialized:
FreeCADGui.addLanguagePath("/path/to/translations")
FreeCADGui.updateLocale()

Plik InitGui.py nie ma atrybutu plik, więc nie jest łatwo znaleźć względną lokalizację folderu tłumaczeń. Łatwym sposobem na obejście tego problemu jest zaimportowanie innego pliku z tego samego folderu, a następnie wykonanie w tym pliku polecenia:

FreeCADGui.addLanguagePath(os.path.join(os.path.dirname(__file__), "translations"))
FreeCADGui.updateLocale()

Wewnątrz każdej klasy poleceń FreeCAD

  • Dodaj następującą linię, na początku pliku:
def QT_TRANSLATE_NOOP(context, text):
    return text
  • Przetłumacz 'MenuText' i 'Tooltip' polecenia w ten sposób:
def GetResources(self):
    return {'Pixmap'  : "path/to/icon.svg"),
            'MenuText': QT_TRANSLATE_NOOP("CommandName", "My Command"),
            'ToolTip' : QT_TRANSLATE_NOOP("CommandName", "Describes what the command does"),
            'Accel'   : "Shift+A"
    }

gdzie "CommandName" jest nazwą polecenia, zdefiniowaną przez:

FreeCADGui.addCommand('CommandName', My_Command_Class())

Zbierz wszystkie ciągi z twojego modułu

  • Będziesz potrzebował zainstalowanych w systemie narzędzi lupdate, lconvert, lrelease i pylupdate. W dystrybucjach Linuksa są one zwykle dostępne w pakietach o nazwach pyside-tools lub pyside2-tools. W niektórych systemach lupdate nazywa się lupdate4 lub lupdate5 lub lupdate-qt4 lub podobnie. To samo dotyczy innych narzędzi. Możesz użyć wersji Qt4 lub Qt5 według własnego uznania. W Qt6 nie ma oddzielnego systemu tłumaczeń dla plików środowiska Python, lupdate jest używany do wyodrębniania łańcuchów ze wszystkich typów plików źródłowych.
  • Jeśli masz pliki .ui, musisz najpierw uruchomić lupdate:
lupdate *.ui -ts translations/uifiles.ts

To działa rekurencyjnie i znajdzie pliki .ui wewnątrz wszystkich twoich katalogów.

  • Jeśli masz pliki .py, musisz również uruchomić pylupdate:
pylupdate *.py -ts translations/pyfiles.ts
  • Jeśli wykonałeś obie operacje, musisz teraz połączyć te dwa pliki w jeden:
lconvert -i translations/uifiles.ts translations/pyfiles.ts -o translations/MyModule.ts
* Sprawdź zawartość trzech plików .ts, aby upewnić się, że zawierają one łańcuchy znaków, a następnie możesz usunąć zarówno pyfiles.ts, jak i uifiles.ts.
  • Możesz to wszystko zrobić w jednym skrypcie bash, tak jak poniżej:
#!/bin/sh
lupdate *.ui -ts translations/uifiles.ts
pylupdate *.py -ts translations/pyfiles.ts
lconvert -i translations/uifiles.ts translations/pyfiles.ts -o translations/MyModule.ts
rm translations/pyfiles.ts
rm translations/uifiles.ts

Przesłanie pliku .ts do platformy tłumaczeniowej

Nadszedł czas, aby zlecić tłumaczenie Twojego pliku .ts. Możesz założyć konto na publicznej platformie tłumaczeniowej, takiej jak Crowdin lub Transifex, lub możesz skorzystać z naszego istniejącego konta FreeCAD-addons na Crowdin, które ma już wielu użytkowników, a zatem jest większa szansa, że Twój plik zostanie przetłumaczony szybko i przez ludzi, którzy znają FreeCAD.

Jeśli chcesz udostępnić swój plik na koncie FreeCAD Crowdin, skontaktuj się z użytkownikiem Yorik na forum FreeCAD.

Uwaga: niektóre platformy, takie jak Crowdin, mogą zintegrować się z GitHubem i wykonać wszystkie procesy z punktów 2, 3 i 4 automatycznie. W tym celu nie można korzystać z konta FreeCAD Crowdin. Będziesz musiał założyć własne konto.

Scalanie tłumaczeń

Kiedy Twój plik .ts został przetłumaczony, choćby częściowo, możesz pobrać tłumaczenia ze strony:

  • Zazwyczaj pobierasz plik .zip zawierający jeden plik .ts na każdy język.
  • Umieść wszystkie przetłumaczone pliki .ts, razem ze swoim podstawowym plikiem .ts, w folderze translations/.

Kompilacja tłumaczeń

Teraz uruchom program lrelease dla każdego pliku, który posiadasz:

lrelease "translations/Draft_de.ts"
lrelease "translations/Draft_fr.ts"
lrelease "translations/Draft_pt-BR.ts"

Możesz zautomatyzować ten proces:

for f in translations/*_*.ts
do
    lrelease "translations/$f"
done

Powinieneś znaleźć jeden plik .qm dla każdego przetłumaczonego pliku .ts. Pliki .qm będą używane przez Qt i FreeCAD w czasie pracy.

To wszystko, czego potrzebujesz. Zauważ, że niektóre części Twojego środowiska pracy nie mogą być tłumaczone w locie, jeśli zdecydujesz się na zmianę języka. Jeśli tak jest, będziesz musiał ponownie uruchomić FreeCAD, aby nowy język został zastosowany.

Testowanie tłumaczeń

  1. Przełącz FreeCAD na język, który przetłumaczyłeś (np. niemiecki)
  2. Załaduj tłumaczenie do FreeCAD, np. FreeCADGui.addTranslationPath("/path/to/the/folder/containing/qmfile")
  3. Przetestuj coś, np. FreeCAD.Qt.translate("twój kontekst", "jakiś ciąg znaków")

Wynik: To powinno dać ci niemieckie tłumaczenie. Jeśli to działa dobrze, to znaczy, że podstawowa konfiguracja jest w porządku. Wtedy możemy przyjrzeć się czemuś innemu. Na przykład, nazwy poleceń powinny zawsze używać specjalnego kontekstu, który jest nazwą polecenia zarejestrowanego we FreeCAD.

Istotne uwagi

  • Upewnij się, że używasz *kontekstu* i *ciągu znaków*, które rzeczywiście znajdują się w pliku ts/qm.

Wygodniejszy skrypt

Yorik utrzymuje wygodny skrypt dla środowiska pracy BIM, który może zbierać, wysyłać i pobierać pliki ts. Możesz po prostu skopiować i dostosować ten skrypt do swojego środowiska pracy:

https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py

Szczegóły techniczne i obsługa zaawansowana

W powyższych przykładach używane są dwie oddzielne funkcje: translate() i QT_TRANSLATE_NOOP. Możesz również natknąć się na tr() i QT_TR_NOOP, które automatycznie podają argument "kontekst" na podstawie miejsca wywołania. Te dwie pary funkcji są zasadniczo różne.

translate() i tr() wykonują dwa oddzielne zadania: w czasie działania wykonują rzeczywiste tłumaczenie z przekazanego im łańcucha na końcowy przetłumaczony łańcuch. Jest to prawda niezależnie od tego, czy podano im łańcuch literalny, zmienną czy stałą: wyszukiwanie odbywa się dynamicznie i w czasie rzeczywistym podczas wykonywania kodu. Jednakże, zapewniają one dodatkową funkcję nie związaną z czasem rzeczywistym: są rozpoznawane przez narzędzie pylupdate. Jeśli (i tylko jeśli) zawierają literał łańcuchowy, to jest on wyodrębniany przez narzędzie. TYLKO literały łańcuchowe są wyodrębniane przez pylupdate. -- jeśli zostanie przekazana zmienna, to jest ona ignorowana przez narzędzie pylupdate. Qt będzie próbowało zapewnić tłumaczenie w czasie wykonywania, ale będzie to działać tylko wtedy, gdy jakiś inny fragment kodu wywoła jedną z funkcji tłumaczących z łańcuchem, który ma być przetłumaczony, tak aby pylupdate mógł go wydobyć. Zauważ, że kod z łańcuchem literalnym nie musi być w rzeczywistości wykonywany, musi po prostu istnieć jako linia kodu gdzieś w pliku: pylupdate nie wykonuje żadnej analizy ani egzekucji kodu, po prostu wykonuje wyszukiwanie i ekstrakcję łańcucha.

W przeciwieństwie do nich, QT_TRANSLATE_NOOP i QT_TR_NOOP nie robią nic w czasie wykonywania: są dosłownymi "no-ops" i są całkowicie ignorowane przez działający kod. Ich jedynym zastosowaniem jest oznaczenie dosłownego łańcucha do ekstrakcji przez pylupdate: nigdy nie ma sensu umieszczać zmiennej wewnątrz wywołania jednej z tych funkcji, nie będzie to miało żadnego efektu. Używa się ich w sytuacjach, gdy translate() lub tr() zostaną wywołane ze zmienną zawierającą tekst do przetłumaczenia. Na przykład, każdy kod, który jest używany do tworzenia poleceń lub właściwości, użyje funkcji typu NOOP wokół tekstu menu poleceń lub etykiety narzędzia, lub docstring właściwości: w czasie działania, gdy FreeCAD wyświetla te elementy użytkownikowi, wywołuje translate(): dosłowne ciągi muszą być wyodrębnione przez pylupdate w punkcie tworzenia, na przykład:

def GetResources(self):
    return {'Pixmap'  : "path/to/icon.svg",
            'MenuText': QT_TRANSLATE_NOOP("CommandName", "My Command"),
            'ToolTip' : QT_TRANSLATE_NOOP("CommandName", "Describes what the command does"),
            'Accel'   : "Shift+A"
    }

W tym zastosowaniu słownik zwracany przez tę funkcję jest dosłownie w czasie pracy:

{ 
    'Pixmap'  : "path/to/icon.svg",
    'MenuText': "My Command",
    'ToolTip' : "Describes what the command does",
    'Accel'   : "Shift+A"
}

Nie ma odniesienia do żadnego typu informacji o tłumaczeniu. Kiedy FreeCAD faktycznie wyświetla te informacje użytkownikowi, pseudokod wygląda następująco:

for command in commands:
    resources = command.GetResources()
    menu_text = translate(resources['MenuText'])

W tym przypadku, lupdate nie może wydobyć żadnego łańcucha z wywołania translate(), ponieważ odwołuje się ono do zmiennej. Zatem lupdate ignoruje to wywołanie, ale w czasie wykonywania Qt szuka łańcucha, który został mu przekazany. Tak długo, jak gdzieś w kodzie znajduje się wywołanie jednej z funkcji tłumaczących z pasującym dosłownym łańcuchem (w tym przypadku w funkcji GetResources()), to wywołanie tłumaczenia powiedzie się.

Aby sprawdzić, czy wyodrębniane są oczekiwane ciągi znaków, możesz ręcznie uruchomić polecenie pylupdate:

pylupdate myfile.py -ts outfile.ts

Plik outfile.ts będzie zawierał zestaw ciągów znaków, które są przesyłane do CrowdIn w celu przetłumaczenia.

Ważne odnośniki

  • Dlaczego warto i jak tłumaczyć funkcje openCommand() (forum thread).

Powiązane strony