israel-dryer/ttkbootstrap

Add translations for any hard-coded text within widgets

NewbieXvwu opened this issue · 80 comments

Some custom windows (such as themed dialog boxes) are used in your program, but it seems that some of their contents are in English and cannot be changed. Would you mind providing an way to translate it to other languages? I am willing to help translate it into Chinese.

@NewbieXvwu, thank you for submitting. This is a good catch.

Can you try running this code and post the results? I've read that this tcl/tk package can do the translations automatically... that would be nice.

import tkinter as tk

def translate(text):
    return root.tk.eval("namespace eval ::tk {::msgcat::mc %s}" % text)


root = tk.Tk()
tk.Button(root, text=translate("retry")).pack()
root.mainloop()

image

User test
FB_IMG_1642719122574.jpg

User test
FB_IMG_1642720277598.jpg

My operating system is in Chinese, but it doesn't seem to translate... Maybe the translation function only supports some languages.

Another possibility is that the translation function calls Google translation. Chinese mainland can not visit Google translation.

Maybe only Linux system supports this function? I don't have a Linux environment.

@NewbieXvwu I forced my system to german swiss and it worked on Windows 11. For some reason, I can't get it to work with the Chinese locale codes though.

What result do you get if you run this?

from gettext import gettext

result = gettext('Retry')
print(result)

Python 3.10.1 (tags/v3.10.1:2cd268a, Dec 6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
from gettext import gettext
result = gettext('Retry')
print(result)
Retry

Maybe there is no Chinese translation in tk?

My idea is this: add a file similar to "en_US.json". When the program needs to read hard coded data, read it from the file, and automatically read the file similar to "zh_CN.json" by judging the system language setting to realize translation. This may be a supplement to TK's own translation function.

@NewbieXvwu, I think this is something that is important to fix, but I'll need some time to consider the best way to implement something like this. At a minimum I could probably add a module that includes translations of standard labels used in custom widgets and dialogs.

@NewbieXvwu, It looks like this mapping can be done within tcl/tk. I used google translate so hopefully it is right.

image

I used the first command listed below, the 2nd one could be used to map multiple translations at once for a single locale.

::msgcat::mcset locale src-string ?translate-string?
Sets the translation for src-string to translate-string in the specified locale and the current namespace. If translate-string is not specified, src-string is used for both. The function returns translate-string.

::msgcat::mcmset locale src-trans-list
Sets the translation for multiple source strings in src-trans-list in the specified locale and the current namespace. src-trans-list must have an even number of elements and is in the form {src-string translate-string ?src-string translate-string ...?} ::msgcat::mcmset can be significantly faster than multiple invocations of ::msgcat::mcset. The function returns the number of translations set.

If you will compile a list of all the translations you think I will need, I'll add it in a test module and we can see how it works in the application. Then we can test how it might scale to the other languages that are not supported (apparently) by tkinter.

I think your idea is very good. What can I do for you now?

I hope to separate the translation file from the code (similar to "zh_CN.json"), so that even people without Python basics can participate in the translation.

I heard TK offered a "zh_cn.msg" file can help with translation.

I don't see one. But we can definitely use one of these as a template.

https://github.com/tcltk/tk/tree/main/library%2Fmsgs

Would you mind taking one of these msg files and converting it to Chinese?

Otherwise, if it's too big a task, I might be able to run a script to look them up.

Wait a moment. I'm trying translate from en.msg.

zh_cn.zip
I am not a professional translator. This translation may contain errors. It is based on "en.msg".

I tested it on Kubuntu virtual machine. It doesn't seem to be a problem with Windows itself.
image

When I am free, I may be able to help translate your documents.

If possible also add translation for widgets.

weblate offers a free hosting plan, I don't know if it's compatible with tk inter

https://docs.weblate.org/en/latest/index.html
https://docs.weblate.org/en/latest/user/files.html

@NewbieXvwu, two things... I created a check that loads the custom msg file if it's in a list of locales... which there is only one currently.

image

The other thing is that the msg file has to map between English and Chinese as you can see from this Russian msg file. I added it in manually for retry in the msg file, but we'll have to add the Chinese translation after the English word for all of them.

image

@antrrax I tried weblate, but it doesn't seem compatible with msg format.

zh_cn.zip

@israel-dryer I'm finished.

@israel-dryer What should be "langdir" in your code?

@israel-dryer What should be "langdir" in your code?

That's the directory that contains the msg file

"zh_cn.msg"?But it seems not work......
image

My py file:

import tkinter as tk
langdir = r'C:\Users\Administrator\Desktop\LanguageTest'
def translate(text):
return root.tk.eval(f"namespace eval ::tk ::msgcat::mc {text}")
root = tk.Tk()
root.tk.eval("namespace eval ::tk ::msgcat::mclocale zh_cn")
locale = root.tk.eval("namespace eval ::tk ::msgcat::mclocale")
if locale in ['zh_cn']:
root.tk.eval(f"namespace eval ::tk ::msgcat::mcload {langdir}")
tk.Button(root, text=translate('retry')).pack()
root.mainloop()

Please view my document translation project.I have translated the index.md.

@israel-dryer @NewbieXvwu

Regarding tk msg files, wouldn't it be more appropriate to make a PR on Tk's own github, with this file in chinese?
https://github.com/tcltk/tk/tree/main/library/msgs

And then @israel-dryer creates another separate translation just for the ttkbootstrap widgets/dialogs. That way you can choose the best translation platform.

github pages:
https://github.com/tcltk/tcl/tree/main/library/msgs
https://github.com/tcltk/tk/tree/main/library/msgs


Linux - Default directory of msg files :

/usr/share/tcltk/tcl8.6/msgs
/usr/share/tcltk/tk8.6/msgs

Windows - Default directory of msg files :

%AppData%\Local\Programs\Python\Python310\tcl\tcl8.6\msgs
%AppData%\Local\Programs\Python\Python310\tcl\tk8.6\msgs

@israel-dryer @NewbieXvwu

Regarding tk msg files, wouldn't it be more appropriate to make a PR on Tk's own github, with this file in chinese?
https://github.com/tcltk/tk/tree/main/library/msgs

And then @israel-dryer creates another separate translation just for the ttkbootstrap widgets/dialogs. That way you can choose the best translation platform.

github pages:
https://github.com/tcltk/tcl/tree/main/library/msgs
https://github.com/tcltk/tk/tree/main/library/msgs


Linux - Default directory of msg files :

/usr/share/tcltk/tcl8.6/msgs
/usr/share/tcltk/tk8.6/msgs

Windows - Default directory of msg files :

%AppData%\Local\Programs\Python\Python310\tcl\tcl8.6\msgs
%AppData%\Local\Programs\Python\Python310\tcl\tk8.6\msgs

I think this is a great idea. Though, it will take some time for it to flow through to tkinter, it will eventually and everyone would benefit. In the meantime I will still likely add supplemental files.

@israel-dryer I'm translating your document.I'm now trying to launch a pr.

@israel-dryer I'm translating your document.I'm now trying to launch a pr.

Wow. That index file looks good. Unfortunately I can't read any of it. But I'm very happy that you've taken the time to do it.

image

image

"fossil" how appropriate 😂

How can I launch a PR on tcl-lang.org?

My py file:

import tkinter as tk langdir = r'C:\Users\Administrator\Desktop\LanguageTest' def translate(text): return root.tk.eval(f"namespace eval ::tk ::msgcat::mc {text}") root = tk.Tk() root.tk.eval("namespace eval ::tk ::msgcat::mclocale zh_cn") locale = root.tk.eval("namespace eval ::tk ::msgcat::mclocale") if locale in ['zh_cn']: root.tk.eval(f"namespace eval ::tk ::msgcat::mcload {langdir}") tk.Button(root, text=translate('retry')).pack() root.mainloop()

Strange. I tried your code with the file and it worked fine.

Maybe try not settings the locale, since it should already be set correct?

image

Please provide a copyable code snippet,So I can carry out convenient tests.Thanks.

Maybe my folder parameters are wrong. Do I need to change my file name?

Maybe my folder parameters are wrong. Do I need to change my file name?

my filename is zh_CN.msg

OK.Now it works.
image

What else do I need to do before formally adding this to ttkbootstrap?

If you want to create a localization branch of ttkbootstrap, we can work on this together.

For now I think the msg file can go into a folder called "src/ttkbootstrap/localization/msgs"

Some items we'll need to review

  • additional translations for words used in ttkbootstrap dialogs
  • adding localization functions to the localization module; writing python wrappers on the tk::msgcat api
  • applying the translation function to all text that is intended to be localized
  • test compiling with pyinstaller.. I want to avoid having users have to add non py assets to their setup if possible

@NewbieXvwu actually, if you can just do a pull request to add the msg file. That should be enough. I'll send you a list of a few more additional words to translate, and then I'll take care of implementing the msgcat api.

A few things I'll need translated:

  • Should be of data type
  • Invalid data type
  • Number cannot be greater than
  • Out of Range
  • Submit
  • Delete
  • Next
  • Previous
  • Open
  • Close
  • Add
  • Remove
  • Family
  • Weight
  • Slant
  • Effects
  • Preview
  • Size

OK.I have translated.

Have you finished testing my PR?Are there any other jobs before merge?

Have you finished testing my PR?Are there any other jobs before merge?

Working on it now. The docs are built using an automatic process on readthedocs, so I need to make sure the automated build process works as expected with this new setup.

I tested it on the readthedocs website and there seems to be a problem. I have little experience in this field.

I tested it on the readthedocs website and there seems to be a problem. I have little experience in this field.

Yeah, I've never done multi-language documentation either, so I guess we're both learning something new here. After about 2 days of trying to get this to work with readthedocs and was about to give up... but I finally found something that I think will work. It's not quite as clean and separated as I would like, but it works from several experiments I've done and shows the behavior that I would expect, including translating navigation elements and allowing for Chinese character search.

https://github.com/ultrabug/mkdocs-static-i18n

Aside from the configuration setup, all of the Chinese files would live in the same directory as the English files, except that they would have a zh suffix...

index.md
index.zh.md

Have you considered how to handle the API documentation? I'm currently generating nearly all of that directly from the docstring.

You have done a lot of work on this already and it is very much appreciated. I hate to ask you to move and rename your files again, but if you could I believe this can get finished. I've tested the configuration and file setup on a test project so I know that it works now.

Otherwise, I can probably write a short python script that will rename and move the files to the appropriate location in the module and then submit a PR to your branch to bring in those changes. I can also setup the configuration files for the new setup.

I'd like to test it on your branch and into a test environment in readthedocs before I bring it into the main branch.

Anyway, let me know if you can move and rename the files, or if you'd rather me script it. I'm fine either way.

@NewbieXvwu, I think I've got things working.

I moved all the files and renamed them. The links appear to have migrated as well.

I added google translations to the navbar, so feel free to correct them if they are wrong.
msedge_zBXiYlZlui

The site switches very smoothly from english to chinese.

I'll do a PR on your branch for these changes.

@NewbieXvwu woohooo!!! we have some progress. This is now building successfully to readthedocs.
https://ttkbootstrap.readthedocs.io/en/latest/zh/

msedge_mO4NkRkqu9

Your work was excellent, congratulations for your dedication.

I did a PR for the pt translation.

But it might be more appropriate to create a 'pt_br' file, as Brazilian Portuguese is different from Portuguese from Portugal


I did some tests here.

Some questions about the translation:
The Fonts dialog has some terms with no translation option yet.
01

Regarding the term "Slant" in the font dialog, it might be more suitable for internationalization purposes to change it to "Style". As it is the most common term that users are used to and would facilitate the reuse of the term for translation.
00
Ps: In the file I send I used the Portuguese term for Style.


In the future, do you intend to add translation for the Color dialog, the DatePickerDialog, and the Tableview?

Your work was excellent, congratulations for your dedication.

I did a PR for the pt translation.
But it might be more appropriate to create a 'pt_br' file, as Brazilian Portuguese is different from Portuguese from Portugal

I did some tests here.

Some questions about the translation: The Fonts dialog has some terms with no translation option yet. 01

Regarding the term "Slant" in the font dialog, it might be more suitable for internationalization purposes to change it to "Style". As it is the most common term that users are used to and would facilitate the reuse of the term for translation. 00 Ps: In the file I send I used the Portuguese term for Style.

In the future, do you intend to add translation for the Color dialog, the DatePickerDialog, and the Tableview?

If you see something that you think should get a translation, submit a PR of the change.

  1. Add the mapping in the msg file.
  2. Add the new word or phrase in the README.txt in the localization module (this will help us keep track of the words that need translated - it's going to be a group effort).
  3. Use the following method on the text you want to translate:
MessageCatalog.translate("text you want to translate")
MessageCatalog.translate("text you want to translate")

I searched for the terms to be translated. Here is the sample in Brazilian Portuguese.

pt_br.msg:

::msgcat::mcset pt_br "Ok" "Ok"
::msgcat::mcset pt_br "Retry" "Repetir"
::msgcat::mcset pt_br "Delete" "Exlcuir"
::msgcat::mcset pt_br "Next" "Próximo"
::msgcat::mcset pt_br "Prev" "Anterior"
::msgcat::mcset pt_br "Yes" "Sim"
::msgcat::mcset pt_br "No" "Não"
::msgcat::mcset pt_br "Open" "Abrir"
::msgcat::mcset pt_br "Close" "Fechar"
::msgcat::mcset pt_br "Add" "Adicionar"
::msgcat::mcset pt_br "Remove" "Remover"
::msgcat::mcset pt_br "Submit" "Enviar"
::msgcat::mcset pt_br "Family" "Família"
::msgcat::mcset pt_br "Weight" "Espessura"
::msgcat::mcset pt_br "Slant" "Estilo"
::msgcat::mcset pt_br "Effects" "Efeitos"
::msgcat::mcset pt_br "Preview" "Visualizar"
::msgcat::mcset pt_br "Size" "Tamanho"
::msgcat::mcset pt_br "Should be of data type" "Deve ser do tipo de dados"
::msgcat::mcset pt_br "Invalid data type" "Tipo de dados inválido"
::msgcat::mcset pt_br "Number cannot be greater than" "O número não deve ser maior que"
::msgcat::mcset pt_br "Out of range" "Fora do limite"
::msgcat::mcset pt_br "Submit" "Enviar"
::msgcat::mcset pt_br "Delete" "Excluir"
::msgcat::mcset pt_br "Next" "Próximo"
::msgcat::mcset pt_br "Previous" "Anterior"
::msgcat::mcset pt_br "Open" "Abrir"
::msgcat::mcset pt_br "Close" "Fechar"
::msgcat::mcset pt_br "Add" "Adicionar"
::msgcat::mcset pt_br "Remove" "Remover"
::msgcat::mcset pt_br "Family" "Família"
::msgcat::mcset pt_br "Weight" "Espessura"
::msgcat::mcset pt_br "Slant" "Estilo"
::msgcat::mcset pt_br "Effects" "Efeitos"
::msgcat::mcset pt_br "Preview" "Visualizar"
::msgcat::mcset pt_br "Size" "Tamanho"
::msgcat::mcset pt_br "The quick brown fox jumps over the lazy dog." "A rápida raposa marrom pula sobre o cachorro preguiçoso."

::msgcat::mcset pt_br "Font Selector" "Seletor de Fontes"
::msgcat::mcset pt_br "normal" "normal"
::msgcat::mcset pt_br "bold"  "negrito"
::msgcat::mcset pt_br "roman" "romano"
::msgcat::mcset pt_br "italic" "itálico"
::msgcat::mcset pt_br "underline" "sublinhado"
::msgcat::mcset pt_br "overstrike" "taxado"
::msgcat::mcset pt_br "Color Chooser" "Seletor de Cores"
::msgcat::mcset pt_br "Advanced" "Avançado"
::msgcat::mcset pt_br "Themd" "Tema"
::msgcat::mcset pt_br "Standard" "Básicas"
::msgcat::mcset pt_br "Current" "Atual"
::msgcat::mcset pt_br "New" "Nova"
::msgcat::mcset pt_br "Red" "Vermelho"
::msgcat::mcset pt_br "Green" "Verde"
::msgcat::mcset pt_br "Blue" "Azul"
::msgcat::mcset pt_br "color dropper" "Selecionador de cores (conta-gotas)"
::msgcat::mcset pt_br "January" "Janeiro"
::msgcat::mcset pt_br "February" "Fevereiro"
::msgcat::mcset pt_br "March" "Março"
::msgcat::mcset pt_br "April" "Abril"
::msgcat::mcset pt_br "May" "Maio"
::msgcat::mcset pt_br "June" "Junho"
::msgcat::mcset pt_br "July" "Julho"
::msgcat::mcset pt_br "August" "Agosto"
::msgcat::mcset pt_br "September" "Setembro"
::msgcat::mcset pt_br "October" "Outubro"
::msgcat::mcset pt_br "November" "Novembro"
::msgcat::mcset pt_br "December" "Dezembro"
::msgcat::mcset pt_br "Su" "D"
::msgcat::mcset pt_br "Mo" "S"
::msgcat::mcset pt_br "Tu" "T"
::msgcat::mcset pt_br "We" "Q"
::msgcat::mcset pt_br "Th" "Q"
::msgcat::mcset pt_br "Fr" "S"
::msgcat::mcset pt_br "Sa" "S"
::msgcat::mcset pt_br "Search" "Buscar"
::msgcat::mcset pt_br "Page" "Página"
::msgcat::mcset pt_br "of" "de"
::msgcat::mcset pt_br "Reset table" "Resetar Tabela"
::msgcat::mcset pt_br "Columns" "Colunas"
::msgcat::mcset pt_br "Move" "Mover"
::msgcat::mcset pt_br "Align" "Alinhar"
::msgcat::mcset pt_br "Hide column" "Ocultar coluna"
::msgcat::mcset pt_br "Delete column" "Excluir coluna"
::msgcat::mcset pt_br "Show All" "Exibir todas"
::msgcat::mcset pt_br "Move to left" "Mover para esquerda"
::msgcat::mcset pt_br "Move to right" "Mover para direira"
::msgcat::mcset pt_br "Move to first" "Mover para o início"
::msgcat::mcset pt_br "Move to last" "Mover para o fim"
::msgcat::mcset pt_br "Align left" "Alinhar à esquerda"
::msgcat::mcset pt_br "Align center" "Alinhar ao centro"
::msgcat::mcset pt_br "Align right" "Alinhar à direita"
::msgcat::mcset pt_br "Sort" "Classificar"
::msgcat::mcset pt_br "Filter" "Filtrar"
::msgcat::mcset pt_br "Export" "Exportar"
::msgcat::mcset pt_br "Move" "Mover"
::msgcat::mcset pt_br "Align" "Alinhar"
::msgcat::mcset pt_br "Delete selected rows" "Excluir linhas selecionadas"
::msgcat::mcset pt_br "Sort Ascending" "Ordem crescente"
::msgcat::mcset pt_br "Sort Descending" "Ordem decrescente"
::msgcat::mcset pt_br "Clear filters" "Limpar filtros"
::msgcat::mcset pt_br "Filter by cell's value" "Filtrar pelo valor da célula"
::msgcat::mcset pt_br "Hide select rows" "Ocultar linha selecionada"
::msgcat::mcset pt_br "Show only select rows" "Exibir somente as linhas selecionadas"
::msgcat::mcset pt_br "Export all records" "Exportar todos os dados"
::msgcat::mcset pt_br "Export current page" "Exportar página atual"
::msgcat::mcset pt_br "Export current selection" "Exportar seleção atual"
::msgcat::mcset pt_br "Export records in filter" "Exportar dados do filtro"
::msgcat::mcset pt_br "Move up" "Mover para cima"
::msgcat::mcset pt_br "Move down" "Mover para baixo"
::msgcat::mcset pt_br "Move to top" "Mover para o início"
::msgcat::mcset pt_br "Move to bottom" "Mover para o fim"
::msgcat::mcset pt_br "Align left" "Alinhar à esquerda"
::msgcat::mcset pt_br "Align center" "Alinhar ao centro"
::msgcat::mcset pt_br "Align right" "Alinhar à direita"

on the recommended site to generate the language code:
https://wiki.freepascal.org/Language_Codes

uses hyfem to separate language from country (pt-br)
in your chinese sample, the file used the underscore symbol (zh_cn). Which symbol should be used "-" or "_"?


The windows title cannot be translated. It shows an error there try to use this
"MessageCatalog.translate()"


From what I've observed, you search for the translation by the term and not by a code.

In your Readme file, list some repeated terms. The question remains, how does the code deal with this? Using the term to search for a translation is a serious problem, as there are some words that in English can have more than one meaning depending on the context. Ex: glass, can
The correct thing would be to create code for the terms to be translated.

Another example, "Slant" the literal translation would be "inclinado". However, in fluent Portuguese, no one would use this term to refer to the style of a font. ("Slant" - "inclinado") would be used in the context of a "sloping" street (rua "inclinada")

Reusing terms is problematic, as translation depends on context.


Complement;

Another problem, in English some words do not have gender or plural variation.

term: New

English example: New Folder
Portuguese translation: Nova Pasta

English example: New Document
Portuguese translation: Novo Documento

English example (plural): New Documents
Portuguese translation (plural): Novos Documentos

Portuguese translation: 'Novo' (masculine)
Portuguese translation: 'Nova' (feminine)


In fluent Portuguese 'Weight' refers to the mass of an object. So the literal translation would be correct in the mass context, but wrong in the font property context. Reusing English terms will have translation context problems. The correct thing is that each sentence has its own translation.

That's why it's important to use code to search for a term/phrase

MessageCatalog.translate("text you want to translate")

I searched for the terms to be translated. Here is the sample in Brazilian Portuguese.

pt_br.msg:

::msgcat::mcset pt_br "Ok" "Ok"
::msgcat::mcset pt_br "Retry" "Repetir"
::msgcat::mcset pt_br "Delete" "Exlcuir"
::msgcat::mcset pt_br "Next" "Próximo"
::msgcat::mcset pt_br "Prev" "Anterior"
::msgcat::mcset pt_br "Yes" "Sim"
::msgcat::mcset pt_br "No" "Não"
::msgcat::mcset pt_br "Open" "Abrir"
::msgcat::mcset pt_br "Close" "Fechar"
::msgcat::mcset pt_br "Add" "Adicionar"
::msgcat::mcset pt_br "Remove" "Remover"
::msgcat::mcset pt_br "Submit" "Enviar"
::msgcat::mcset pt_br "Family" "Família"
::msgcat::mcset pt_br "Weight" "Espessura"
::msgcat::mcset pt_br "Slant" "Estilo"
::msgcat::mcset pt_br "Effects" "Efeitos"
::msgcat::mcset pt_br "Preview" "Visualizar"
::msgcat::mcset pt_br "Size" "Tamanho"
::msgcat::mcset pt_br "Should be of data type" "Deve ser do tipo de dados"
::msgcat::mcset pt_br "Invalid data type" "Tipo de dados inválido"
::msgcat::mcset pt_br "Number cannot be greater than" "O número não deve ser maior que"
::msgcat::mcset pt_br "Out of range" "Fora do limite"
::msgcat::mcset pt_br "Submit" "Enviar"
::msgcat::mcset pt_br "Delete" "Excluir"
::msgcat::mcset pt_br "Next" "Próximo"
::msgcat::mcset pt_br "Previous" "Anterior"
::msgcat::mcset pt_br "Open" "Abrir"
::msgcat::mcset pt_br "Close" "Fechar"
::msgcat::mcset pt_br "Add" "Adicionar"
::msgcat::mcset pt_br "Remove" "Remover"
::msgcat::mcset pt_br "Family" "Família"
::msgcat::mcset pt_br "Weight" "Espessura"
::msgcat::mcset pt_br "Slant" "Estilo"
::msgcat::mcset pt_br "Effects" "Efeitos"
::msgcat::mcset pt_br "Preview" "Visualizar"
::msgcat::mcset pt_br "Size" "Tamanho"
::msgcat::mcset pt_br "The quick brown fox jumps over the lazy dog." "A rápida raposa marrom pula sobre o cachorro preguiçoso."

::msgcat::mcset pt_br "Font Selector" "Seletor de Fontes"
::msgcat::mcset pt_br "normal" "normal"
::msgcat::mcset pt_br "bold"  "negrito"
::msgcat::mcset pt_br "roman" "romano"
::msgcat::mcset pt_br "italic" "itálico"
::msgcat::mcset pt_br "underline" "sublinhado"
::msgcat::mcset pt_br "overstrike" "taxado"
::msgcat::mcset pt_br "Color Chooser" "Seletor de Cores"
::msgcat::mcset pt_br "Advanced" "Avançado"
::msgcat::mcset pt_br "Themd" "Tema"
::msgcat::mcset pt_br "Standard" "Básicas"
::msgcat::mcset pt_br "Current" "Atual"
::msgcat::mcset pt_br "New" "Nova"
::msgcat::mcset pt_br "Red" "Vermelho"
::msgcat::mcset pt_br "Green" "Verde"
::msgcat::mcset pt_br "Blue" "Azul"
::msgcat::mcset pt_br "color dropper" "Selecionador de cores (conta-gotas)"
::msgcat::mcset pt_br "January" "Janeiro"
::msgcat::mcset pt_br "February" "Fevereiro"
::msgcat::mcset pt_br "March" "Março"
::msgcat::mcset pt_br "April" "Abril"
::msgcat::mcset pt_br "May" "Maio"
::msgcat::mcset pt_br "June" "Junho"
::msgcat::mcset pt_br "July" "Julho"
::msgcat::mcset pt_br "August" "Agosto"
::msgcat::mcset pt_br "September" "Setembro"
::msgcat::mcset pt_br "October" "Outubro"
::msgcat::mcset pt_br "November" "Novembro"
::msgcat::mcset pt_br "December" "Dezembro"
::msgcat::mcset pt_br "Su" "D"
::msgcat::mcset pt_br "Mo" "S"
::msgcat::mcset pt_br "Tu" "T"
::msgcat::mcset pt_br "We" "Q"
::msgcat::mcset pt_br "Th" "Q"
::msgcat::mcset pt_br "Fr" "S"
::msgcat::mcset pt_br "Sa" "S"
::msgcat::mcset pt_br "Search" "Buscar"
::msgcat::mcset pt_br "Page" "Página"
::msgcat::mcset pt_br "of" "de"
::msgcat::mcset pt_br "Reset table" "Resetar Tabela"
::msgcat::mcset pt_br "Columns" "Colunas"
::msgcat::mcset pt_br "Move" "Mover"
::msgcat::mcset pt_br "Align" "Alinhar"
::msgcat::mcset pt_br "Hide column" "Ocultar coluna"
::msgcat::mcset pt_br "Delete column" "Excluir coluna"
::msgcat::mcset pt_br "Show All" "Exibir todas"
::msgcat::mcset pt_br "Move to left" "Mover para esquerda"
::msgcat::mcset pt_br "Move to right" "Mover para direira"
::msgcat::mcset pt_br "Move to first" "Mover para o início"
::msgcat::mcset pt_br "Move to last" "Mover para o fim"
::msgcat::mcset pt_br "Align left" "Alinhar à esquerda"
::msgcat::mcset pt_br "Align center" "Alinhar ao centro"
::msgcat::mcset pt_br "Align right" "Alinhar à direita"
::msgcat::mcset pt_br "Sort" "Classificar"
::msgcat::mcset pt_br "Filter" "Filtrar"
::msgcat::mcset pt_br "Export" "Exportar"
::msgcat::mcset pt_br "Move" "Mover"
::msgcat::mcset pt_br "Align" "Alinhar"
::msgcat::mcset pt_br "Delete selected rows" "Excluir linhas selecionadas"
::msgcat::mcset pt_br "Sort Ascending" "Ordem crescente"
::msgcat::mcset pt_br "Sort Descending" "Ordem decrescente"
::msgcat::mcset pt_br "Clear filters" "Limpar filtros"
::msgcat::mcset pt_br "Filter by cell's value" "Filtrar pelo valor da célula"
::msgcat::mcset pt_br "Hide select rows" "Ocultar linha selecionada"
::msgcat::mcset pt_br "Show only select rows" "Exibir somente as linhas selecionadas"
::msgcat::mcset pt_br "Export all records" "Exportar todos os dados"
::msgcat::mcset pt_br "Export current page" "Exportar página atual"
::msgcat::mcset pt_br "Export current selection" "Exportar seleção atual"
::msgcat::mcset pt_br "Export records in filter" "Exportar dados do filtro"
::msgcat::mcset pt_br "Move up" "Mover para cima"
::msgcat::mcset pt_br "Move down" "Mover para baixo"
::msgcat::mcset pt_br "Move to top" "Mover para o início"
::msgcat::mcset pt_br "Move to bottom" "Mover para o fim"
::msgcat::mcset pt_br "Align left" "Alinhar à esquerda"
::msgcat::mcset pt_br "Align center" "Alinhar ao centro"
::msgcat::mcset pt_br "Align right" "Alinhar à direita"

on the recommended site to generate the language code: https://wiki.freepascal.org/Language_Codes

uses hyfem to separate language from country (pt-br) in your chinese sample, the file used the underscore symbol (zh_cn). Which symbol should be used "-" or "_"?

The windows title cannot be translated. It shows an error there try to use this "MessageCatalog.translate()"

From what I've observed, you search for the translation by the term and not by a code.

In your Readme file, list some repeated terms. The question remains, how does the code deal with this? Using the term to search for a translation is a serious problem, as there are some words that in English can have more than one meaning depending on the context. Ex: glass, can The correct thing would be to create code for the terms to be translated.

Another example, "Slant" the literal translation would be "inclinado". However, in fluent Portuguese, no one would use this term to refer to the style of a font. ("Slant" - "inclinado") would be used in the context of a "sloping" street (rua "inclinada")

Reusing terms is problematic, as translation depends on context.

Complement;

Another problem, in English some words do not have gender or plural variation.

term: New

English example: New Folder Portuguese translation: Nova Pasta

English example: New Document Portuguese translation: Novo Documento

English example (plural): New Documents Portuguese translation (plural): Novos Documentos

Portuguese translation: 'Novo' (masculine) Portuguese translation: 'Nova' (feminine)

In fluent Portuguese 'Weight' refers to the mass of an object. So the literal translation would be correct in the mass context, but wrong in the font property context. Reusing English terms will have translation context problems. The correct thing is that each sentence has its own translation.

That's why it's important to use code to search for a term/phrase

I think the MessageCatalog component has a very limited application... localizing button text and labels and other standard application elements. The 'msg' file acts almost like a python dictionary where it looks the term used and attempts to find a match. It's also case sensitive from what I can tell, so it treats "ok", "Ok", and "OK" as 3 separate tokens. This is why you may see a repeated term with different capitalization applied. It's a simplistic mechanism for translating your buttons and labels via the use of msg files instead of putting that business logic in your code.

When looking for a translation, I would go for the meaning and not necessarily a literal translation. I'm guessing there is a typical way that different localities handle ok, cancel, new, etc... So, if you are familiar with that culture, I would leave it up to you to convey the correct meaning with the mapped term.

Can you show the error you get when translating the title?

Can you show the error you get when translating the title?

Dialog titles are in the class initializer definition.

file: ..../ttkbootstrap/dialogs/dialogs.py
line 882:
def __init__(self, title="Font Selector", parent=None):

wrong way to try to translate the title:
def __init__(self, title=MessageCatalog.translate("Font Selector"), parent=None):


file: ..../ttkbootstrap/dialogs/colorchooser.py
line 512:
def __init__(self, parent=None, title="Color Chooser", initialcolor=None):

This is why you may see a repeated term with different capitalization applied

In the new README file that is on github, all repeated terms are identical.

the term 'Family' is repeated, and is identical: it has the same letters and case.

This is why you may see a repeated term with different capitalization applied

In the new README file that is on github, all repeated terms are identical.

the term 'Family' is repeated, and is identical: it has the same letters and case.

Ok. Then it must is have been an oversight on my part, copying and pasting.

Can you show the error you get when translating the title?

Dialog titles are in the class initializer definition.

file: ..../ttkbootstrap/dialogs/dialogs.py
line 882:
def __init__(self, title="Font Selector", parent=None):

wrong way to try to translate the title:
def __init__(self, title=MessageCatalog.translate("Font Selector"), parent=None):


file: ..../ttkbootstrap/dialogs/colorchooser.py
line 512:
def __init__(self, parent=None, title="Color Chooser", initialcolor=None):

You can translate the term above the super() and then pass the translated term into the call to super()

With this modification it worked:

from ttkbootstrap.localization import MessageCatalog


     def __init__(self, title="Font Selector", parent=None):
         title = MessageCatalog.translate(title)
         super().__init__(parent=parent, title=title)

I did the translation of the terms.

In ColorChooserDialog
Cancel button, cut translated string


In DateEntry, I didn't find a way to translate the name of the months and the abbreviation of the days of the week.
It would be interesting to add this option


FontDialog all ok


In the tableview there are many symbols next to the names, at first I chose to include the symbols in the translation. But the symbol "🞨" of the "Delete column" and "Delete selected rows" did not accept the translation. So I would have to format these strings in another way.
How do you prefer this formatting, can it be f-string with three single quotes? (to allow using single/double quotes in the English string content):

f'''🞨 {MessageCatalog.translate("Delete selected rows")}'''


See the files as they were after this initial modification, once you decide on which string formatting pattern I will redo:
https://www.mediafire.com/file/objrhl68zwt01rw/ttkbootstrap_src.zip/file


00

01

02

04

03

  • We probably need to remove the fixed size of the buttons on the Color Chooser and let the geometry manager decide. That should fix the cut off text. I'll have to check the other dialogs to make sure this is setup consistently, especially now that the button text will vary in size.

  • There is probably a date localization in the datetime module that we can explore for localized dates, months, and week names, etc.

  • I think the f strings are perfect. This is not going to be running on anything less than Python 3.7 and I use f strings in many other places.

Posting for reference on getting localized date info

https://stackoverflow.com/a/26927760

Using the tip from the link above, I changed the dialogs file to display the month name in the default language of the user's system.

I tested it here on linux on the real machine, and on win 10 on a virtual machine in the pt_br language and it worked. I don't know how it would behave in other languages.

See if you agree with the resolution:

line 11:
import locale

line 609:
locale.setlocale(locale.LC_ALL, locale.setlocale(locale.LC_TIME,''))

line 746

    def _set_title(self):
        _titledate = f'{self.date.strftime("%B %Y")}'
        self.titlevar.set(value=_titledate.capitalize())

View the modified file:
dialogs.py.zip
01

@israel-dryer How can I translate the toast documation?

The API docs are tricky because the documentation is in the docstring. My best solution is to copy the docstring from the source document and then put it into this format using markdown. This version is live, so you can see what it looks like online. I was not able to replicate all of the look & feel of the original without resorting to HTML, which would be too tedious to maintain.

The markdown
https://github.com/israel-dryer/ttkbootstrap/blob/master/docs/api/toast.zh.md

What it looks like online
https://ttkbootstrap.readthedocs.io/en/latest/zh/api/toast/

@israel-dryer

On the documentation page, would it be possible to restrict the search to the selected language only?
As is now the search results appear duplicated (English and Chinese)

For example, search for the term:

utility module

@israel-dryer

On the documentation page, would it be possible to restrict the search to the selected language only? As is now the search results appear duplicated (English and Chinese)

For example, search for the term:

utility module

Unfortunately, it doesn't look like that feature is supported yet. https://github.com/ultrabug/mkdocs-static-i18n#compatibility-with-the-search-plugin

However, once the documents are fully translated, it should not be an issue since the word 'Utility' will not be shown in English characters.

@israel-dryer Can I read another file according to the language selection when reading the string in the file?

@israel-dryer Can I read another file according to the language selection when reading the string in the file?

I'm not sure what you mean. Can you give an example?

Can I store descriptions in two different languages in the source file and read them on demand?

Can I store descriptions in two different languages in the source file and read them on demand?

Yes, this is possible, and believe it or not, very simple. Here's a minimal example. You just have to pass in the locale and a list of word pairs.

from ttkbootstrap.localization import MessageCatalog
from ttkbootstrap.dialogs import Messagebox

msgs = [
    'OK', 'Yep',
    'Cancel', 'Nope'
]

MessageCatalog.set_many('en_us', *msgs)
Messagebox.okcancel('Do you like this custom translation?')

This produces the following window
python_PDTuUDgcLS

When trying to figure out how to do this, I did find a bug in the function, so I'll push that update to github now, and I'll make sure it's part of 1.6.2.

@israel-dryer You may not understand what I mean... I mean that I can't translate the contents of all "style guide" sections because they are rendered by reading data from py source files. Can I store text in two languages in py source files for translation?

Oh. I'm not sure yet. Because we are talking about the contents of the python files, we might be better off approaching this with the pot/po files and the gettext module, or babel library. However, I'd have to do some research on that personally. I've not done large-scale translation projects before, and that will require some setup for it to work smoothly.

@israel-dryer Perhaps you can use a GitHub Action script to automatically generate a markdown file from the py file at each commit. I know a little bit about GitHub Action.