diff --git a/.gitignore b/.gitignore index 30a71a4..cc56eea 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ *.swp *.swo .* +*.mo +*~ +po/messages.pot diff --git a/TRANSLATION.md b/TRANSLATION.md new file mode 100644 index 0000000..064c10f --- /dev/null +++ b/TRANSLATION.md @@ -0,0 +1,60 @@ +# 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 .. + + # run test + +## 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 `.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. diff --git a/bin/kano-apps b/bin/kano-apps index c02956e..4970ae7 100755 --- a/bin/kano-apps +++ b/bin/kano-apps @@ -2,7 +2,7 @@ # kano-apps # -# Copyright (C) 2014, 2015 Kano Computing Ltd. +# Copyright (C) 2014-2016 Kano Computing Ltd. # License: http://www.gnu.org/licenses/gpl-2.0.txt GNU GPL v2 # @@ -15,6 +15,12 @@ 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 = [dir_path] + sys.path + locale_path = os.path.join(dir_path, 'locale') + else: + locale_path = None + +import kano_i18n.init +kano_i18n.init.install('kano-apps', locale_path) from kano.gtk3.kano_dialog import KanoDialog from kano.logging import logger @@ -50,18 +56,18 @@ def check_for_expand_partition(): # Check if partition has been expanded if not is_partition_expanded(device): # Show dialogue - head = "Do you want to reboot now?" - msg = "A reboot is required to complete the installation of Kano" \ - " OS so it can access all the space on the SD card." + head = _("Do you want to reboot now?") + msg = _("A reboot is required to complete the installation of Kano" +\ + " OS so it can access all the space on the SD card.") kdialog = KanoDialog( head, msg, { - "LATER": { + _("LATER"): { "return_value": False, "color": "red" }, - "REBOOT": { + _("REBOOT"): { "return_value": True, "color": "green" }, @@ -107,29 +113,29 @@ def batch_install(apps, icon_only=False): def args_parse(): if len(sys.argv) >= 2: - desc = "An application hub for Kano OS." + desc = _("An application hub for Kano OS.") parser = argparse.ArgumentParser(description=desc) parser.set_defaults(cmd=None) subparsers = parser.add_subparsers(dest="cmd") - install_help = "Use this to install applications" + install_help = _("Use this to install applications") install = subparsers.add_parser("install", help=install_help) install.add_argument("--no-gui", dest="gui", action="store_const", const=False, default=True, - help="Run without the GUI") + help=_("Run without the GUI")) install.add_argument("--icon-only", dest="icon_only", action="store_const", const=True, default=False, - help="Install just the app icon") + help=_("Install just the app icon")) install.add_argument("apps", metavar="APP", type=str, nargs="+", - help="A list of applications to install") + help=_("A list of applications to install")) - update_help = "Check for possible updates of all installed " \ - "applications" + update_help = _("Check for possible updates of all installed " +\ + "applications") subparsers.add_parser("check-for-updates", help=update_help) - tutorial_help = "Shows a tutorial that explains how to add icons to" \ - "the desktop" + tutorial_help = _("Shows a tutorial that explains how to add icons to " +\ + "the desktop") subparsers.add_parser("icon-tutorial", help=tutorial_help) return parser.parse_args() diff --git a/debian/control b/debian/control index 6c8cbac..c4d1f00 100644 --- a/debian/control +++ b/debian/control @@ -3,12 +3,12 @@ Maintainer: Team Kano Section: misc Priority: optional Standards-Version: 3.9.4 -Build-Depends: debhelper (>=9.0.0), python +Build-Depends: debhelper (>=9.0.0), python, gettext Package: kano-apps Architecture: all Depends: ${misc:Depends}, python, python-gi, kano-toolset (>= 1.2-5), - kano-themes, kano-profile (>=1.3-6) + kano-themes, kano-profile (>=1.3-6), kano-i18n Replaces: kano-desktop (<< 1.0-60) Breaks: kano-desktop (<< 1.0-60) Conflicts: kano-extras diff --git a/debian/rules b/debian/rules index 4647c9c..8bf5e42 100755 --- a/debian/rules +++ b/debian/rules @@ -1,4 +1,5 @@ #!/usr/bin/make -f %: + cd po && make dh $@ --with python2 diff --git a/kano_apps/AppGrid.py b/kano_apps/AppGrid.py index c3cb7f5..f4f2c5c 100644 --- a/kano_apps/AppGrid.py +++ b/kano_apps/AppGrid.py @@ -1,6 +1,6 @@ # AppGrid.py # -# Copyright (C) 2014 Kano Computing Ltd. +# Copyright (C) 2014-2016 Kano Computing Ltd. # License: http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 # @@ -29,8 +29,8 @@ def __init__(self, apps, main_win): want_more_app = { "type": "app", - "title": "Want more apps?", - "tagline": "Go to Kano World to install more", + "title": _("Want more apps?"), + "tagline": _("Go to Kano World to install more"), "slug": "want-more", "origin": "-", @@ -51,8 +51,8 @@ def __init__(self, apps, main_win): last_page = 0 - self._cat_names = ["latest", "code", "games", "media", "tools", - "others", "experimental"] + self._cat_names = [N_("latest"), N_("code"), N_("games"), N_("media"), N_("tools"), + N_("others"), N_("experimental")] self._categories = {} self._apps = {} @@ -73,7 +73,7 @@ def __init__(self, apps, main_win): # Prepare tabs for the apps for cat in sorted_categories: self._categories[cat] = AppGrid(main_win, self) - label = Gtk.Label(cat.upper()) + label = Gtk.Label(_(cat).upper()) ebox = Gtk.EventBox() ebox.add(label) ebox.connect("realize", self._set_cursor_to_hand_cb) @@ -244,10 +244,10 @@ def refresh(self): if self._is_on_desktop(): self.set_image(Gtk.Image.new_from_file(self._RM_IMG_PATH)) - self.set_tooltip_text("Remove from desktop") + self.set_tooltip_text(_("Remove from desktop")) else: self.set_image(Gtk.Image.new_from_file(self._ADD_IMG_PATH)) - self.set_tooltip_text("Add to desktop") + self.set_tooltip_text(_("Add to desktop")) self.show_all() @@ -415,10 +415,10 @@ def _launch_app(self, cmd, args): # The execvp should not return, so if we reach this point, # there was an error. message = KanoDialog( - "Error", - "Unable to start the application.", + _("Error"), + _("Unable to start the application."), { - "OK": { + _("OK"): { "return_value": 0, "color": "red" } @@ -437,7 +437,7 @@ def _setup_desc_button(self): more_btn.props.margin_right = 21 more_btn.get_style_context().add_class('more-button') more_btn.connect("clicked", self._show_more_cb) - more_btn.set_tooltip_text("More information") + more_btn.set_tooltip_text(_("More information")) more_btn.connect("realize", self._set_cursor_to_hand_cb) self._entry.pack_start(more_btn, False, False, 0) @@ -459,7 +459,7 @@ def _setup_remove_button(self): remove_btn.props.margin_right = 21 remove_btn.get_style_context().add_class('more-button') remove_btn.connect("clicked", self._uninstall_cb) - remove_btn.set_tooltip_text("Remove") + remove_btn.set_tooltip_text(_("Remove")) remove_btn.connect("realize", self._set_cursor_to_hand_cb) remove_btn.connect("enter-notify-event", self._open_bin_cb) remove_btn.connect("leave-notify-event", self._close_bin_cb) @@ -490,7 +490,7 @@ def _setup_update_button(self): update_btn.props.margin_right = 21 update_btn.get_style_context().add_class('more-button') update_btn.connect("clicked", self._update_cb) - update_btn.set_tooltip_text("Update app") + update_btn.set_tooltip_text(_("Update app")) update_btn.connect("realize", self._set_cursor_to_hand_cb) self._entry.pack_start(update_btn, False, False, 0) self._entry.reorder_child(update_btn, 2) @@ -509,7 +509,7 @@ def _show_more_cb(self, widget): self._app["title"], self._app['description'] if "description" in self._app else self._app['tagline'], { - "OK, GOT IT": { + _("OK, GOT IT"): { "return_value": 0, "color": "green" } @@ -532,14 +532,14 @@ def _entry_click_cb(self, ebox, event): def _uninstall_cb(self, event): confirmation = KanoDialog( - title_text="Removing {}".format(self._app["title"]), - description_text="This application will be uninstalled and " + - "removed from apps. Do you wish to proceed?", + title_text=_("Removing {}").format(self._app["title"]), + description_text=_("This application will be uninstalled and " + + "removed from apps. Do you wish to proceed?"), button_dict={ - "YES": { + _("YES"): { "return_value": 0 }, - "NO": { + _("NO"): { "return_value": -1, "color": "red" } @@ -553,7 +553,7 @@ def _uninstall_cb(self, event): if rv < 0: return - prompt = "Uninstalling {}".format(self._app["title"]) + prompt = _("Uninstalling {}").format(self._app["title"]) pw = get_sudo_password(prompt, self._window) if pw is None: return @@ -578,14 +578,14 @@ def _install_cb(self): def _update_cb(self, widget): confirmation = KanoDialog( - title_text="Updating {}".format(self._app["title"]), - description_text="This application will be updated " + - "Do you wish to proceed?", + title_text=_("Updating {}").format(self._app["title"]), + description_text=_("This application will be updated " + + "Do you wish to proceed?"), button_dict={ - "YES": { + _("YES"): { "return_value": 0 }, - "NO": { + _("NO"): { "return_value": -1, "color": "red" } diff --git a/kano_apps/AppInstaller.py b/kano_apps/AppInstaller.py index 74faa12..22b2c25 100644 --- a/kano_apps/AppInstaller.py +++ b/kano_apps/AppInstaller.py @@ -91,11 +91,11 @@ def _download_app(self): self._tmp_data_file = app_data_file self._tmp_icon_file = app_icon_file except AppDownloadError as err: - head = "Unable to download the application" + head = _("Unable to download the application") dialog = KanoDialog( head, str(err), { - "OK": { + _("OK"): { "return_value": 0 }, }, @@ -111,15 +111,15 @@ def _download_app(self): def _installed_check(self): if is_app_installed(self._app): - head = "{} is already installed".format(self._app["title"]) - desc = "Would you like to update it?" + head = _("{} is already installed").format(self._app["title"]) + desc = _("Would you like to update it?") dialog = KanoDialog( head, desc, { - "YES": { + _("YES"): { "return_value": 0 }, - "NO": { + _("NO"): { "return_value": -1 } }, @@ -137,7 +137,7 @@ def _installed_check(self): def _get_sudo_pw(self): if self._pw is None: - self._pw = get_sudo_password("Installing {}".format(self._app["title"])) + self._pw = get_sudo_password(_("Installing {}").format(self._app["title"])) return self._pw is not None return True @@ -160,21 +160,21 @@ def _install(self): if not self._icon_only and self._add_to_desktop: add_to_desktop(self._app) - head = "Done!" - message = self._app["title"] + " installed successfully! " + \ - "Look for it in the Apps launcher." + head = _("Done!") + message = _("%s installed successfully! " + \ + "Look for it in the Apps launcher.") % self._app["title"] else: - head = "Installation failed" - message = self._app["title"] + " cannot be installed at " + \ + head = _("Installation failed") + message = _("%s cannot be installed at " + \ "the moment. Please make sure your kit is connected " + \ "to the internet and there is enough space left on " + \ - "your card." + "your card.") % self._app["title"] dialog = KanoDialog( head, message, { - "OK": { + _("OK"): { "return_value": 0 }, }, diff --git a/kano_apps/AppManage.py b/kano_apps/AppManage.py index 2f624ca..985acdd 100644 --- a/kano_apps/AppManage.py +++ b/kano_apps/AppManage.py @@ -67,7 +67,7 @@ def uninstall_packages(app, sudo_pwd=None): pkgs = " ".join(app["packages"]) - cmd = "rxvt -title 'Uninstalling {}' -e bash -c ".format(app["title"]) + cmd = ("rxvt -title " + _("'Uninstalling {}'") + " -e bash -c ").format(app["title"]) if sudo_pwd: cmd += "'echo {} | sudo -S apt-get purge -y {}'".format(sudo_pwd, pkgs) else: @@ -118,15 +118,15 @@ def download_app(app_id_or_slug): icon_path = '/tmp/{}.{}'.format(app_id_or_slug, icon_file_type) rv, err = download_url(data['icon_url'], icon_path) if not rv: - msg = "Unable to download the application ({})".format(err) + msg = _("Unable to download the application ({})").format(err) raise AppDownloadError(msg) # Check if the app is going to run well on the hardware if 'min_performance_score' in data and \ has_min_performance(data['min_performance_score']): - msg = "{} won't be downloaded ".format(data['title']) + \ - "because the hardware is not performant enough" + msg = _("{} won't be downloaded " + \ + "because the hardware is not performant enough").format(data['title']) raise AppDownloadError(msg) # Cleanup the JSON file diff --git a/kano_apps/MainWindow.py b/kano_apps/MainWindow.py index d28c7df..43c2daa 100644 --- a/kano_apps/MainWindow.py +++ b/kano_apps/MainWindow.py @@ -57,7 +57,7 @@ def __init__(self, install=None, icon_only=False, tutorial=False): # Setup widgets self.set_decorated(True) - self._top_bar = TopBar("Apps", self._win_width, False) + self._top_bar = TopBar(_("Apps"), self._win_width, False) self._top_bar.set_close_callback(Gtk.main_quit) self.set_titlebar(self._top_bar) @@ -101,12 +101,12 @@ def _show_icon_tutorial(self): save_app_state_variable('kano-apps', 'icon-tutorial-shown', True) kdialog = KanoDialog( - "Add more apps to the desktop", - "Click the '+' button to the right of the app name to " - "make it appear on the desktop. You can remove it again " - "by clicking on 'x'.", + _("Add more apps to the desktop"), + _("Click the '+' button to the right of the app name to " +\ + "make it appear on the desktop. You can remove it again " +\ + "by clicking on 'x'."), { - "OK, GOT IT": { + _("OK, GOT IT"): { "return_value": 0, "color": "green" } diff --git a/kano_apps/UIElements.py b/kano_apps/UIElements.py index ea1f1d0..c04cf72 100644 --- a/kano_apps/UIElements.py +++ b/kano_apps/UIElements.py @@ -43,7 +43,7 @@ def get_sudo_password(heading, parent=None): entry.set_visibility(False) kdialog = KanoDialog( title_text=heading, - description_text="Enter your system password - default is kano:", + description_text=_("Enter your system password - default is kano:"), widget=entry, has_entry=True, global_style=True, @@ -57,12 +57,12 @@ def get_sudo_password(heading, parent=None): while not pam.authenticate(getpass.getuser(), pw): fail = KanoDialog( title_text=heading, - description_text="The password was incorrect. Try again?", + description_text=_("The password was incorrect. Try again?"), button_dict={ - "YES": { + _("YES"): { "return_value": 0 }, - "CANCEL": { + _("CANCEL"): { "return_value": -1, "color": "red" } @@ -79,7 +79,7 @@ def get_sudo_password(heading, parent=None): entry.set_visibility(False) kdialog = KanoDialog( title_text=heading, - description_text="Re-enter your system password - default is kano:", + description_text=_("Re-enter your system password - default is kano:"), widget=entry, has_entry=True, global_style=True, diff --git a/po/Makefile b/po/Makefile new file mode 100644 index 0000000..c7abe4b --- /dev/null +++ b/po/Makefile @@ -0,0 +1,36 @@ +APPNAME=kano-apps +ORG="Kano Computing Ltd." + +MSGLANGS=$(notdir $(wildcard *po)) +MSGOBJS=$(addprefix ../locale/,$(MSGLANGS:.po=/LC_MESSAGES/$(APPNAME).mo)) + +.PHONY: clean_locales messages + +build: $(MSGOBJS) + +update: $(MSGLANGS) + +clean_locales: + rm -rf ../locale + +clean: clean_locales + rm -f messages.pot + +define run-xgettext +xgettext -f PYPOTFILES -L Python --force-po -o messages.pot \ + --keyword=N_ --package-name=$(APPNAME) --copyright-holder=$(ORG) +endef + +messages: + $(run-xgettext) + +messages.pot: + $(run-xgettext) + +%.po: messages.pot + msgmerge -N -U $*.po messages.pot + touch $*.po + +../locale/%/LC_MESSAGES/$(APPNAME).mo: clean_locales + mkdir -p $(dir $@) + msgfmt -c -o $@ $*.po diff --git a/po/PYPOTFILES b/po/PYPOTFILES new file mode 100644 index 0000000..c619503 --- /dev/null +++ b/po/PYPOTFILES @@ -0,0 +1,7 @@ +../bin/kano-apps +../kano_apps/AppGrid.py +../kano_apps/AppInstaller.py +../kano_apps/AppManage.py +../kano_apps/MainWindow.py +../kano_apps/UIElements.py + diff --git a/po/ja.po b/po/ja.po new file mode 100644 index 0000000..9eeef29 --- /dev/null +++ b/po/ja.po @@ -0,0 +1,254 @@ +# Japanese translations for kano-apps package. +# Copyright (C) 2016 Kano Computing Ltd. +# This file is distributed under the same license as the kano-apps package. +# Choppin Antoine , 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: kano-apps\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-06-03 21:15+0900\n" +"PO-Revision-Date: 2016-06-02 00:15+0900\n" +"Last-Translator: Choppin Antoine \n" +"Language-Team: Japanese\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: ../bin/kano-apps:59 +msgid "Do you want to reboot now?" +msgstr "今再起動しますか?" + +#: ../bin/kano-apps:60 +msgid "" +"A reboot is required to complete the installation of Kano OS so it can " +"access all the space on the SD card." +msgstr "" +"Kano OSのインストールを完了するには、SDカード容量の全てが利用できるよう、再起" +"動が必要です。" + +#: ../bin/kano-apps:66 +msgid "LATER" +msgstr "後で" + +#: ../bin/kano-apps:70 +msgid "REBOOT" +msgstr "再起動" + +#: ../bin/kano-apps:116 +msgid "An application hub for Kano OS." +msgstr "Kano OSアプリのハブ" + +#: ../bin/kano-apps:121 +msgid "Use this to install applications" +msgstr "アプリをインストールする" + +#: ../bin/kano-apps:126 +msgid "Run without the GUI" +msgstr "GUI無しで起動" + +#: ../bin/kano-apps:129 +msgid "Install just the app icon" +msgstr "アプリのアイコンのみインストール" + +#: ../bin/kano-apps:131 +msgid "A list of applications to install" +msgstr "インストール可能なアプリ一覧" + +#: ../bin/kano-apps:133 +msgid "Check for possible updates of all installed applications" +msgstr "インストール済みアプリのアップデート確認" + +#: ../bin/kano-apps:137 +msgid "Shows a tutorial that explains how to add icons to the desktop" +msgstr "デスクトップにアイコンを追加する為のチュートリアル" + +#: ../kano_apps/AppGrid.py:32 +msgid "Want more apps?" +msgstr "他のアプリ欲しい?" + +#: ../kano_apps/AppGrid.py:33 +msgid "Go to Kano World to install more" +msgstr "Kanoワールドで他のアプリをゲットしよう" + +#: ../kano_apps/AppGrid.py:54 +msgid "latest" +msgstr "最新" + +#: ../kano_apps/AppGrid.py:54 +msgid "code" +msgstr "コード" + +#: ../kano_apps/AppGrid.py:54 +msgid "games" +msgstr "ゲーム" + +#: ../kano_apps/AppGrid.py:54 +msgid "media" +msgstr "メディア" + +#: ../kano_apps/AppGrid.py:54 +msgid "tools" +msgstr "ツール" + +#: ../kano_apps/AppGrid.py:55 +msgid "others" +msgstr "その他" + +#: ../kano_apps/AppGrid.py:55 +msgid "experimental" +msgstr "実験中" + +#: ../kano_apps/AppGrid.py:247 +msgid "Remove from desktop" +msgstr "デスクトップから削除" + +#: ../kano_apps/AppGrid.py:250 +msgid "Add to desktop" +msgstr "デスクトップに追加" + +#: ../kano_apps/AppGrid.py:418 +msgid "Error" +msgstr "エラー" + +#: ../kano_apps/AppGrid.py:419 +msgid "Unable to start the application." +msgstr "アプリを起動できません。" + +#: ../kano_apps/AppGrid.py:421 ../kano_apps/AppInstaller.py:98 +#: ../kano_apps/AppInstaller.py:177 +msgid "OK" +msgstr "了解" + +#: ../kano_apps/AppGrid.py:440 +msgid "More information" +msgstr "追加情報" + +#: ../kano_apps/AppGrid.py:462 +msgid "Remove" +msgstr "削除" + +#: ../kano_apps/AppGrid.py:493 +msgid "Update app" +msgstr "アプリをアップデート" + +#: ../kano_apps/AppGrid.py:512 ../kano_apps/MainWindow.py:109 +msgid "OK, GOT IT" +msgstr "はい、了解" + +#: ../kano_apps/AppGrid.py:535 +msgid "Removing {}" +msgstr "{}を削除中" + +#: ../kano_apps/AppGrid.py:536 +msgid "" +"This application will be uninstalled and removed from apps. Do you wish to " +"proceed?" +msgstr "このアプリをアンインストールし、アップスから削除されます。続けますか?" + +#: ../kano_apps/AppGrid.py:539 ../kano_apps/AppGrid.py:585 +#: ../kano_apps/AppInstaller.py:119 ../kano_apps/UIElements.py:62 +msgid "YES" +msgstr "はい" + +#: ../kano_apps/AppGrid.py:542 ../kano_apps/AppGrid.py:588 +#: ../kano_apps/AppInstaller.py:122 +msgid "NO" +msgstr "いいえ" + +#: ../kano_apps/AppGrid.py:556 +msgid "Uninstalling {}" +msgstr "{}をアンインストール" + +#: ../kano_apps/AppGrid.py:581 +msgid "Updating {}" +msgstr "{}をアップデート" + +#: ../kano_apps/AppGrid.py:582 +msgid "This application will be updated Do you wish to proceed?" +msgstr "このアプリがアップデートされます。続けますか?" + +#: ../kano_apps/AppInstaller.py:94 +msgid "Unable to download the application" +msgstr "アプリのダウンロードが失敗しました" + +#: ../kano_apps/AppInstaller.py:114 +msgid "{} is already installed" +msgstr "{}はすでにインストール済みです" + +#: ../kano_apps/AppInstaller.py:115 +msgid "Would you like to update it?" +msgstr "アップデートしますか?" + +#: ../kano_apps/AppInstaller.py:140 +msgid "Installing {}" +msgstr "{}をインストール中" + +#: ../kano_apps/AppInstaller.py:163 +msgid "Done!" +msgstr "完了!" + +#: ../kano_apps/AppInstaller.py:164 +#, python-format +msgid "%s installed successfully! Look for it in the Apps launcher." +msgstr "%sは無事にインストールされました!アップラウンチャーから起動できます。" + +#: ../kano_apps/AppInstaller.py:167 +msgid "Installation failed" +msgstr "インストールの失敗" + +#: ../kano_apps/AppInstaller.py:168 +#, python-format +msgid "" +"%s cannot be installed at the moment. Please make sure your kit is connected " +"to the internet and there is enough space left on your card." +msgstr "" +"現在、%sをインストールすることが出来ません。インターネットに接続していること" +"とSDカードの空き容量を確認してください。" + +#: ../kano_apps/AppManage.py:70 +msgid "'Uninstalling {}'" +msgstr "'{}をアンインストール中'" + +#: ../kano_apps/AppManage.py:121 +msgid "Unable to download the application ({})" +msgstr "アプリ({})をダウンロード出来ません" + +#: ../kano_apps/AppManage.py:128 +msgid "{} won't be downloaded because the hardware is not performant enough" +msgstr "ハードウェアのスペックが不十分な為、{}がダウンロード出来ません" + +#: ../kano_apps/MainWindow.py:60 +msgid "Apps" +msgstr "アップス" + +#: ../kano_apps/MainWindow.py:104 +msgid "Add more apps to the desktop" +msgstr "デスクトップに他のアプリを追加しよう" + +#: ../kano_apps/MainWindow.py:105 +msgid "" +"Click the '+' button to the right of the app name to make it appear on the " +"desktop. You can remove it again by clicking on 'x'." +msgstr "" +"アプリの右側の'+'ボタンでアプリをデスクトップに追加できます。'x'をクリックし" +"て、デスクトップから削除できます。" + +#: ../kano_apps/UIElements.py:46 +msgid "Enter your system password - default is kano:" +msgstr "システムパスワードを入力してください(初期パスワードはkanoです):" + +#: ../kano_apps/UIElements.py:60 +msgid "The password was incorrect. Try again?" +msgstr "パスワードが間違っています。やり直す?" + +#: ../kano_apps/UIElements.py:65 +msgid "CANCEL" +msgstr "キャンセル" + +#: ../kano_apps/UIElements.py:82 +msgid "Re-enter your system password - default is kano:" +msgstr "システムパスワードを再度入力してください(初期パスワードはkanoです):" +