Characters and Translation on Plugins

I just discovered unicodes and kinda how they work on Python.
And I am curious if it is possible to detect in which language Krita is running.
This possibly to swap some characters into another set that might make more sense in another language.
Simple stuff like numbers and math symbols like + or - or maybe a word or two.

This because it occurred to me all Krita plugins must be in English only?

1 Like

Hi

why doing complex things and reinvent the wheel ? :thinking:

Grum999

oh there was already a discussion about this.

well it would be easier to set up the plugin to be agnostic and have displayed text entries chosen to be translated no? Exposing a “plugin_translations.py” file to change sounds so much better for a script to act upon than on the real code not to mention correct.

my translation might be extremely bad as I used google translate, but it is integrated with the code and easy to edit and add languages but a way to detect a language would be neat.
This is a simple test for chinese simplified.

language_chinese

1 Like

Currently no access to my computer
But there’s something I don’t understand.

There’s already everything in Python, PyQt and Krita framework to use standardized translations methods.
Scripts don’t really have to know in which langage the user interface is set ; it just use i18n framework and return translated strings

So implement a new way of doing translation is for me really strange…

For example, using this in a script

print(Krita.instance().krita_i18n("File"))

Will print “File” in english and “Fichier” in french
(not tested as not possible for me now to test, but should work)

If you really need to know user language, check for QLocale in Qt documentation

Grum999

1 Like

well to me it seems like a natural thought to have.

I used Google Translate to translate my strings to Portuguese as a test and it did not fail in giving me wibbly wobbly results as always that needed to be corrected to be readable and not be a chuchu train. I can’t imagine i18n automatic translations to have better results.

Also i18n translations do not give me nothing because my system is in English, so I can’t check it. and i have it in English so software does not get automatically translated because they just make gibberish.

What I set up was just this:

just a couple of strings for some languages here but if someone throws me something I could add it quickly because things are set inside to react correctly.

Is this such a bad idea? Honestly I could just make things with just English and it would be just the same as before no?

i18n functionalities doesn’t make “better” translation as there’s no automatic translation.
Translation are made by humans (user, dedicated translators, …)

The Krita’s i18n() method is based on one of the most used standard tools for software internationalization (gettext)

My system is English too, but if I switch to an another language, translation is made properly :slight_smile:
But I agree, changing language in Krita is a little bit boring as Krita need to be restarted to get new locale applied.

I won’t judge, it’s your choice and maybe the best choice for you.

My remark was just that as things already exist, have already made proof of efficiency and could be a better choice.
Also it seems you were not aware of these standards and framework, so, could be a good thing to inform you about it :slight_smile:

For me the best choice is to use standard tools :blush:
Unfortunately, Krita’s i18n() doesn’t allows to load additional language files (.mo files)

Here a simple example made with default Python’s *gettext module


I let you judge the result :stuck_out_tongue:
(note you can’t execute it on your side without .mo files - I can provide you them if you want to be able to test it)

And basically:

  1. It’s fast to execute

  2. you have a lot of dedicated tools for translators to easily provide translations
    Usually tools allows:
    – To know what is translated or not
    – To know if translation is OK or need to be reviewed (in case of doubt)
    – To provides some comment on transalations…
    – To reuse existing translation (ensure consistency between plugin for example…)
    Example of my editor (a really basic one!)

Example of a `.po` file (a simple text file)
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.2.1\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-Basepath: ../..\n"
"Last-Translator: \n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Language: fr_FR\n"
"X-Poedit-SearchPath-0: .\n"

# Maybe need to be reviewed?
msgid "This is a translation test!"
msgstr "Ceci est un test de traduction !"

msgid "Hello!"
msgstr "Bonjour !"
  1. Translators don’t have to understand code
    –They just work from one language file (a template usually in english, but you can start translation from Portuguese if you really want) to another one
    – Most of them are probably already used to work with po/mo files

  2. Developers don’t have to care about translation
    – Continue to use English (or any other language) in source code
    – Just get translated files an put them in resource directory

My only question now is, how to load additional .mo file in Krita’s translation catalog to use Krita’s i18n()?
For what I understand, only plugins provided with Krita can be translated by KDE translator teams.

But for other plugins, how to proceed?
Currently I only see the basic Python module.

Maybe @halla or @tiar can help about that?
Anyway, it seems that without an improvement in Krita main class to add a method like i18n_load_translation() it’s currently not possible.
Or maybe need a tweak?
@AkiR @KnowZero any idea about that? :slight_smile:

Grum999

1 Like

I don’t really have much experience with translating things… maybe through QCoreApplication.installTranslator() or setting QCoreAplication.translate ?

I’ve already took a look this way.
But Qt’s translator class work with dedicated .qm files.
And Krita’s main translation file is .mo files.

Even if there’s some .qm files, it seems krita use gettext for major translation and also libintl (but that’s blurry for me, not really able to find exactly where in Krita’s source code the i18n came from - for Python binding it’s easy to find but for C++ I’m lost in source code)

Grum999

What about overriding translate? And running gettext there to get the mo translations?

I think i18n is from KDE:
https://techbase.kde.org/Development/Tutorials/Localization/i18n

1 Like

Interesting idea
I’ve to dig it

Thanks for the link, I have to take a look on how it’s implemented

What I see is:

And I wasn’t able to load .mo file with QTranslator (but maybe I used it in a wrong way) so I was thinking the default Qt translation system wasn’t used

I’ll try to check this tonight

Grum999

It works :slight_smile:
=> Thanks for the idea! :blush:

Code
import sys
import os.path
import gettext
from krita import *

locale=QLocale()
translationTests=[#-- from plugin translation file
                  'Hello!', 
                  'This is a translation test!',
                  #-- from krita translation file
                  'File',
                  'New',
                  'Open',
                  'Close']

if sys.platform=='linux':
    # where locale files are available in Linux
    kirtaMOFileDirectory=os.path.join(QLibraryInfo.location(QLibraryInfo.PrefixPath),'share/krita/locale')
elif sys.platform=='win32':
    # where locale files are available in Windows
    kirtaMOFileDirectory=os.path.join(QLibraryInfo.location(QLibraryInfo.PrefixPath),'locale')
else:   
    # where locale files are available in macOs?
    raise Exception('Where?')

for langCode in ['fr_FR', 'pt_PT', 'de_DE', 'ja_JP', 'en_GB']:
    # load Krita's main .mo file
    kLangCode=langCode if langCode in ('en_GB', 'zh_CN', 'zh_HK', 'zh_TW') else langCode[:2]
    kLocale=gettext.translation('krita', localedir=kirtaMOFileDirectory, languages=[kLangCode])
    
    # load plugin "test" .mo file
    pLocale=gettext.translation('test', localedir='/home/grum/Temporaire/TempKrita/tmp_pykrita/test_i18n/locales', languages=[langCode])
    # fall back to Krita's locale if nothing found from plugin
    pLocale.add_fallback(kLocale)
    # install locale 
    pLocale.install()
    # set i18n function as replacement for default gettext _() method
    i18n=_
    
    print(f"--Using language: {langCode}")
    if langCode==locale.name():
        print('  > Current user language!')
    
    for toTranslate in translationTests:
        print(f"  {toTranslate} ==> ", i18n(toTranslate))
       
    print()

Overriding the default Krita’s i18n is not the most elegant way, but I didn’t found other solution than the one you’ve proposed

The thing is simple:

  • Load Krita’s main locale file in a dedicated gettext instance
  • Load plugin locale file in a dedicated gettext instance
    – Declare the Krita’s main gettext instance as fall back when unknown translation is found

Then, I can translate dedicated string from plugin and use as fallback Krita’s translation.

Edit:

  1. As most of my plugins currently use i18n I keep this as a solution for later to translate my plugin in French
  2. The best solution still is something provided from Krita API like i18n_load_translation() to load additional translation files :slight_smile:

Grum999

What about overriding QTranslator’s translate function? Then loading it up via installTranslator

I might miss something :slight_smile:

I’m not sure to understand how the overriding of QTranslator translate function could solve the problem.

Quick example of what I did:

class QPluginTranslator(QTranslator):

    def translate(self, context, sourceText, disambiguation=None, n=-1):
        if sourceText in ('Hello!', 'File', 'New'):
            # intercept and force result with something I'm sure to detect the method is called
            return f"{sourceText}==>yes!"
        return super(QPluginTranslator, self).translate(context, sourceText, disambiguation, n)
    
pTranslator=QPluginTranslator()

QApplication.installTranslator(pTranslator)

print(i18n("File"))

And nothing happen.
Doing some additional test, it seems only shortcut are translated by this :thinking:

Grum999

It translates more than just shortcuts, it translates GUI elements. Which my guess is the end goal correct? It just needs to be installed before everything is loaded.

class QPluginTranslator(QTranslator):

    def translate(self, context, sourceText, disambiguation=None, n=-1):
        if sourceText in ('Hello!', 'File', '&OK', 'New'):
            # intercept and force result with something I'm sure to detect the method is called
            return f"{sourceText}==>yes!"
        return super(QPluginTranslator, self).translate(context, sourceText, disambiguation, n)
    
pTranslator=QPluginTranslator()

QApplication.installTranslator(pTranslator)

error_dialog = QtWidgets.QErrorMessage()
error_dialog.showMessage('')

As for direct use via the function. I’ll look into it in more detail during the weekend.