Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i18n hooks and Japanese translation #68

Open
wants to merge 3 commits into
base: jessie
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
*.pyc
*.mo
*~
po/messages.pot
58 changes: 58 additions & 0 deletions TRANSLATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Translation

Translation files are found in the `po/` directory.

## i18n not released yet

Kano OS is not fully i18n-aware and locales are not installed for end users, yet. You can translate this application, but as of now, users will still see the default English message strings.

## How to add a new translation

In this example, we're going to add a French translation:

# install your target locale `fr_FR.utf8` with:
sudo dpkg-reconfigure locales

cd po/
# create messages.pot
make messages

# create fr.po from messages.pot:
msginit -l fr_FR.utf8

# now use your favourite editor to translate fr.po

# build locale files:
make

cd ..

## How to make sure your code is i18n-aware

Add the gettext `_()` macro to all the user-visible message strings in your Python. List the Python source files that contain message strings in `PYPOTFILES`.

If you added new message strings or made changes to existing ones, do `make messages` to keep the template file up-to-date.

After that, merge the existing translations with `make update` and ask your translators to update their translations.

## gettext explained (in 20 seconds)

* User-visible strings in the source are marked with a macro of your choice. Usually, it's `_()`.
* `xgettext` extracts these message strings from your sources and puts them into a template file.
* This template file, usually named `messages.pot`, contains all user-visible strings of the project, but no translations.
* Translators use `msginit` to copy the template file into a new *portable object* file for their language (explained above).
* The translations are put into `<lang>.po`. It's a plain-text file format, you can use any text editor.
* More convenient, specialized `.po`-editors and web-based tools such as Pootle exist, as well.
* If your template file changes, use `msgmerge` to merge your existing translations with the new template, then re-translate the updated messages. Beware of `msgmerge`'s "fuzzy" matches.
* `msgfmt` converts a `.po` file into a binary *message object* file.
* You don't link these `.mo` files with your application binary.
* The `.mo` files are bundled alongside with your software as part of the distribution package.
* During installation, the `.mo` files are copied into the system's locale directory, usually `/usr/share/locale`.
* On startup, your application will look for the message object file that it needs for the current system locale.
* The locale even allows you to provide region-specific translations, e.g. "colour" for en_UK vs "color" for en_US.
* At runtime, all user-visible strings are being replaced with the translations.
* If no message object was found for the system locale, the original strings will be shown.

## To-Do

Pootle or Transifex integration.
7 changes: 7 additions & 0 deletions bin/kano-feedback
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ if __name__ == '__main__' and __package__ is None:
dir_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if dir_path != '/usr':
sys.path.insert(0, dir_path)
locale_path = os.path.join(dir_path, 'locale')
else:
locale_path = None

import kano_i18n.init
kano_i18n.init.install('kano-feedback', locale_path)


from kano_feedback.FeedbackWindow import FeedbackWindow

Expand Down
4 changes: 2 additions & 2 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ Section: misc
Priority: optional
Standards-Version: 3.9.4
Build-Depends: debhelper (>= 9), build-essential, pkg-config, libgtk2.0-dev,
lxpanel, libfm-dev, libkdesk-dev
lxpanel, libfm-dev, libkdesk-dev, gettext

Package: kano-feedback
Architecture: any
Depends: ${misc:Depends}, curl, kano-toolset (>= 2.4.0-1), kano-profile,
kano-video, kano-video-files (>=1.1-2), feh, libkdesk-dev, lsof,
kano-content
kano-content, kano-i18n
Description: A tool for feedback gathering
A tool to allow Kanux users to provide feedback
3 changes: 3 additions & 0 deletions debian/install
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ icon/feedback.png /usr/share/icons/Kano/66x66/apps/
icon/kano-help.png /usr/share/icons/Kano/88x88/apps/

lxpanel-plugin/kano_feedback.so usr/lib/arm-linux-gnueabihf/lxpanel/plugins/

locale/* usr/share/locale/

1 change: 1 addition & 0 deletions debian/rules
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/make -f

%:
cd po && make
dh $@

override_dh_auto_build:
Expand Down
14 changes: 7 additions & 7 deletions kano_feedback/DataSender.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,8 @@ def send_question_response(question_id, answer, interactive=True):
endpoint.
'''

ok_msg_title = 'Thank you'
ok_msg_body = 'We will use your feedback to improve your experience'
ok_msg_title = _('Thank you')
ok_msg_body = _('We will use your feedback to improve your experience')

if interactive and not try_connect() or not try_login():
# The answer will be saved as offline, act as if it was sent correctly
Expand Down Expand Up @@ -481,16 +481,16 @@ def send_question_response(question_id, answer, interactive=True):
return False

retry = KanoDialog(
title_text='Unable to send',
description_text=('Error while sending your feedback. ' \
'Do you want to retry?'),
title_text=_('Unable to send'),
description_text=(_('Error while sending your feedback. ' \
'Do you want to retry?')),
button_dict={
'Close feedback'.upper():
_('Close feedback').upper():
{
'return_value': False,
'color': 'red'
},
'Retry'.upper():
_('Retry').upper():
{
'return_value': True,
'color': 'green'
Expand Down
32 changes: 16 additions & 16 deletions kano_feedback/FeedbackWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def __init__(self, bug_report=False):
'''
Initialises the window, creating a report or contact window
'''
MainWindow.__init__(self, subject='Kano Desktop Feedback Widget')
MainWindow.__init__(self, subject=_('Kano Desktop Feedback Widget'))
self.bug_report = bug_report
if self.bug_report:
self.report_window()
Expand All @@ -38,7 +38,7 @@ def contact_window(self):
delete_tmp_dir()
create_tmp_dir()

ApplicationWindow.__init__(self, 'Contact Us', self.WIDTH, 0.35)
ApplicationWindow.__init__(self, _('Contact Us'), self.WIDTH, 0.35)

screen = Gdk.Screen.get_default()
specific_provider = Gtk.CssProvider()
Expand All @@ -54,7 +54,7 @@ def contact_window(self):
self._grid = Gtk.Grid()

# Create top bar
self._top_bar = TopBar(title="Contact Us", window_width=self.WIDTH,
self._top_bar = TopBar(title=_("Contact Us"), window_width=self.WIDTH,
has_buttons=False)
self._top_bar.set_close_callback(Gtk.main_quit)
self.set_decorated(True)
Expand All @@ -67,7 +67,7 @@ def contact_window(self):
self._text.set_size_request(self.WIDTH, -1)

self._textbuffer = self._text.get_buffer()
self._textbuffer.set_text("Type your feedback here!")
self._textbuffer.set_text(_("Type your feedback here!"))
self._clear_buffer_handler_id = self._textbuffer.connect("insert-text",
self.clear_buffer)

Expand All @@ -94,7 +94,7 @@ def contact_window(self):
border.set_margin_bottom(20)

# Create send button
self._send_button = KanoButton("SEND")
self._send_button = KanoButton(_("SEND"))
self._send_button.set_sensitive(False)
self._send_button.connect("button_press_event", self.send_feedback)
self._send_button.pack_and_align()
Expand All @@ -121,7 +121,7 @@ def report_window(self):
Report window
Contains 2 text views and Take Screenshot, Add Image and Send buttons
'''
ApplicationWindow.__init__(self, 'Report a Problem', self.WIDTH, 0.35)
ApplicationWindow.__init__(self, _('Report a Problem'), self.WIDTH, 0.35)

screen = Gdk.Screen.get_default()
specific_provider = Gtk.CssProvider()
Expand All @@ -134,14 +134,14 @@ def report_window(self):
self._grid = Gtk.Grid()

# Create top bar
self._top_bar = TopBar(title="Report a Problem",
self._top_bar = TopBar(title=_("Report a Problem"),
window_width=self.WIDTH, has_buttons=False)
self._top_bar.set_close_callback(Gtk.main_quit)
self.set_decorated(True)
self.set_titlebar(self._top_bar)

self.entry = Gtk.Entry()
self.entry.props.placeholder_text = "Add subject (optional)"
self.entry.props.placeholder_text = _("Add subject (optional)")
self.entry.set_margin_left(20)
self.entry.set_margin_right(20)
self.entry.set_margin_top(20)
Expand All @@ -155,7 +155,7 @@ def report_window(self):
self._text.set_size_request(self.WIDTH, -1)

self._textbuffer = self._text.get_buffer()
self._textbuffer.set_text("Type your problem here!")
self._textbuffer.set_text(_("Type your problem here!"))

self._clear_buffer_handler_id = self._textbuffer.connect("insert-text",
self.clear_buffer)
Expand All @@ -182,18 +182,18 @@ def report_window(self):
border.set_margin_bottom(20)

# Create take screenshot button
self._screenshot_button = KanoButton("TAKE SCREENSHOT", "blue")
self._screenshot_button = KanoButton(_("TAKE SCREENSHOT"), "blue")
self._screenshot_button.set_sensitive(True)
self._screenshot_button.connect("button_press_event",
self.screenshot_clicked)

# Create attach screenshot button
self._attach_button = KanoButton("ADD IMAGE", "blue")
self._attach_button = KanoButton(_("ADD IMAGE"), "blue")
self._attach_button.set_sensitive(True)
self._attach_button.connect("button_press_event", self.attach_clicked)

# Create send button
self._send_button = KanoButton("SEND")
self._send_button = KanoButton(_("SEND"))
self._send_button.set_sensitive(False)
self._send_button.connect("button_press_event", self.send_feedback)
self._send_button.pack_and_align()
Expand Down Expand Up @@ -245,7 +245,7 @@ def attach_clicked(self, button=None, event=None):
'''
screenshot = None
# Open file manager
dialog = Gtk.FileChooserDialog("Please choose a file", self,
dialog = Gtk.FileChooserDialog(_("Please choose a file"), self,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Expand All @@ -270,7 +270,7 @@ def add_filters(self, dialog):
'''
# Image filter
filter_images = Gtk.FileFilter()
filter_images.set_name("Images")
filter_images.set_name(_("Images"))
filter_images.add_mime_type("image/png")
filter_images.add_mime_type("image/jpeg")
filter_images.add_mime_type("image/gif")
Expand All @@ -283,7 +283,7 @@ def add_filters(self, dialog):

# Any file filter
filter_any = Gtk.FileFilter()
filter_any.set_name("Any files")
filter_any.set_name(_("Any files"))
filter_any.add_pattern("*")
dialog.add_filter(filter_any)

Expand Down Expand Up @@ -350,7 +350,7 @@ def show_screenshot(self, widget, event):
height * 0.5)
image = Gtk.Image.new_from_pixbuf(pixbuf)

dialog = KanoDialog("Screenshot", widget=image)
dialog = KanoDialog(_("Screenshot"), widget=image)
dialog.run()

def pack_screenshot_buttons(self):
Expand Down
32 changes: 16 additions & 16 deletions kano_feedback/MainWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,19 @@ def send_feedback(self, button=None, event=None, body_title=None):
return

if self.bug_report:
title = "Important"
title = _("Important")
description = (
"Your feedback will include debugging information.\n"
"Do you want to continue?"
_("Your feedback will include debugging information.\n" +\
"Do you want to continue?")
)
kdialog = KanoDialog(
title, description,
{
"CANCEL":
_("CANCEL"):
{
"return_value": 1
},
"OK":
_("OK"):
{
"return_value": 0
}
Expand All @@ -86,35 +86,35 @@ def send_feedback(self, button=None, event=None, body_title=None):
self._text.set_sensitive(False)

def lengthy_process():
button_dict = {"OK": {"return_value": self.CLOSE_FEEDBACK}}
button_dict = {_("OK"): {"return_value": self.CLOSE_FEEDBACK}}

if not is_internet():
title = "No internet connection"
description = "Configure your connection"
button_dict = {"OK": {"return_value": self.LAUNCH_WIFI}}
title = _("No internet connection")
description = _("Configure your connection")
button_dict = {_("OK"): {"return_value": self.LAUNCH_WIFI}}
else:
success, error = self.send_user_info(body_title=body_title)
if success:
title = "Info"
description = "Feedback sent correctly"
title = _("Info")
description = _("Feedback sent correctly")
button_dict = \
{
"OK":
_("OK"):
{
"return_value": self.CLOSE_FEEDBACK
}
}
else:
title = "Info"
description = "Something went wrong, error: {}".format(error)
title = _("Info")
description = _("Something went wrong, error: {}").format(error)
button_dict = \
{
"CLOSE FEEDBACK":
_("CLOSE FEEDBACK"):
{
"return_value": self.CLOSE_FEEDBACK,
"color": "red"
},
"TRY AGAIN":
_("TRY AGAIN"):
{
"return_value": self.KEEP_OPEN,
"color": "green"
Expand Down
6 changes: 3 additions & 3 deletions kano_feedback/WidgetWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class WidgetWindow(ApplicationWindow):
WIDTH = 500
HEIGHT_COMPACT = 50
HEIGHT_EXPANDED = 200
SUBJECT = 'Kano Desktop Feedback Widget'
SUBJECT = _('Kano Desktop Feedback Widget')

def __init__(self):
ApplicationWindow.__init__(self, 'widget', self.WIDTH,
Expand Down Expand Up @@ -104,7 +104,7 @@ def _initialise_window(self):

self.app_name_opened = 'feedback-widget-opened'
self.typeahead = None
self.help_tip_message = 'Type your feedback here!'
self.help_tip_message = _('Type your feedback here!')

self.rotating_mode = True
self.in_submit = False
Expand Down Expand Up @@ -183,7 +183,7 @@ def _initialise_window(self):

self._pack_input_widget()

self._send = send = OrangeButton('SEND')
self._send = send = OrangeButton(_('SEND'))
apply_styling_to_widget(send.label, media_dir() + 'css/widget.css')
send.set_sensitive(False)
send.connect('clicked', self._send_clicked)
Expand Down
Loading