I am using kivy's file chooser and when there is a file of a folder with an Hebrew name, it prints gibberish... I want to support different languages if possible. Tried to change the font name in the file chooser, didn't work for me. Can you help me find out what am I doing wrong?
Asked
Active
Viewed 481 times
1
-
1Do you *see* gibberish in the file chooser, or does it *prints* gibberish when you print the selected file path? – noEmbryo Jan 29 '19 at 16:44
-
Both. Currently I am more into fixing the user experience but I want to be able to show the user the correct name and to be able to get it so I can use the selected file – Yotam Hammer Jan 29 '19 at 16:46
2 Answers
3
It's not only FileChooser
- all instances of Label
in Kivy use Roboto
font as a default, which doesn't seem to support Unicode characters. Try running this code:
from kivy.app import App
from kivy.uix.label import Label
class TestApp(App):
def build(self):
return Label(text="עִבְרִית")
if __name__ == '__main__':
TestApp().run()
There are several fonts shipped with Kivy, one of them is DejaVuSans
. Let's use it:
from kivy.app import App
from kivy.uix.label import Label
class TestApp(App):
def build(self):
return Label(text="עִבְרִית", font_name='DejaVuSans.ttf')
if __name__ == '__main__':
TestApp().run()
And now Hebrew is displayed correctly. It doesn't work for Japanese, though. For that language you have to look for another Unicode font, place it in the directory and pass to the font_name
property.
Anyway. How to make FileChooser
use a different font? The simplest way would be binding a method to on_entry_added
event to change properties of a newly created item in the directory tree:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<MyWidget>:
FileChooserListView
id: filechooser
""")
class MyWidget(BoxLayout):
def __init__(self, *args):
Clock.schedule_once(self.update_filechooser_font, 0)
return super().__init__(*args)
def update_filechooser_font(self, *args):
fc = self.ids['filechooser']
fc.bind(on_entry_added=self.update_file_list_entry)
fc.bind(on_subentry_to_entry=self.update_file_list_entry)
def update_file_list_entry(self, file_chooser, file_list_entry, *args):
file_list_entry.ids['filename'].font_name = 'DejaVuSans.ttf'
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()

Nykakin
- 8,657
- 2
- 29
- 42
-
Wow thanks you a kind stranger! one last thing if you may, when I use your solution the Hebrew text is reversed (Hebrew is written from right to left and kivy shows it from left to right) do you know a quick fix? – Yotam Hammer Jan 30 '19 at 20:43
-
1You can align filename to the right using `file_list_entry.ids['filename'].halign = 'right'` but you need to detect if it's actually in Hebrew first. Google says you can do it like [this](https://stackoverflow.com/questions/10664254/the-right-way-to-check-of-a-string-has-hebrew-chars) – Nykakin Jan 30 '19 at 20:50
-
the halign wasn't working since it just moved the reversed Hebrew text to the right side. But with your help and the help of the link you sent, I made a working scrip for that. Thank you so much and I am uploading my solution as a new answer – Yotam Hammer Jan 31 '19 at 07:03
-
@YotamHammer, I did some testing and there's one more thing: besides binding `on_entry_added` event you should also bind the same function to `on_subentry_to_entry` event, or the change only propagate to top-level directories. I updated the code in my answer. – Nykakin Jan 31 '19 at 22:55
-
Yes I saw this too and added it later. Thank you my programmer friend – Yotam Hammer Jan 31 '19 at 23:03
0
This is my solution. Half of the credit goes to Nykakin:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<MyWidget>:
FileChooserListView
id: filechooser
""")
class MyWidget(BoxLayout):
def __init__(self, *args):
Clock.schedule_once(self.update_filechooser_font, 0)
return super(MyWidget, self).__init__(*args)
def update_filechooser_font(self, *args):
fc = self.ids.filechooser
fc.bind(on_entry_added=self.update_file_list_entry)
fc.bind(on_subentry_to_entry=self.update_file_list_entry)
def update_file_list_entry(self, file_chooser, file_list_entry, *args):
file_list_entry.ids.filename.font_name = 'DejaVuSans.ttf'
updated_text = []
# to count where to insert the english letters
english_counter = 0
# the next statements used to split the name to name, extention
splitted = file_list_entry.ids.filename.text.split('.')
extention = ''
if len(splitted) > 2:
name = '.'.join(splitted)
elif len(splitted) == 2:
name = splitted[0]
extention = splitted[1]
else:
name = '.'.join(splitted)
# for each char in the reversed name (extention is always English and need to not be reversed)
for char in name[::-1]:
# if its in Hebrew append it regularly (reversed) and make sure to zero the counter
if u"\u0590" <= char <= u"\u05EA":
updated_text.append(char)
english_counter = 0
# if its an English character append it before the last english word (to un-reverse it) and increase the counter
else:
updated_text.insert(len(updated_text) - english_counter, char)
english_counter += 1
# add the extention in the end if exists
if extention == '':
file_list_entry.ids.filename.text = ''.join(updated_text)
else:
file_list_entry.ids.filename.text = ''.join(updated_text) + '.' + extention
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()

Yotam Hammer
- 127
- 1
- 2
- 8