Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <marco@marcopg.org>2010-08-22 02:45:10 (GMT)
committer Marco Pesenti Gritti <marco@marcopg.org>2010-08-22 02:45:10 (GMT)
commit323478579d1ef91fd3c994b3576beb99fc53a741 (patch)
treee723e57ff2e838221663417bf4cde1f2726b60d7
parent9bbd9992f44690f4a32c916afd39f144aef798b7 (diff)
parentff2c88680481bd16f0906a08a04500ccd217ce80 (diff)
Merge shell module in a subdirectory
-rw-r--r--shell/.gitignore59
-rw-r--r--shell/AUTHORS14
-rw-r--r--shell/COPYING339
-rw-r--r--shell/MAINTAINERS9
-rw-r--r--shell/Makefile.am14
-rw-r--r--shell/README44
-rwxr-xr-xshell/autogen.sh4
-rw-r--r--shell/bin/Makefile.am14
-rw-r--r--shell/bin/sugar-activity21
-rw-r--r--shell/bin/sugar-control-panel28
-rwxr-xr-xshell/bin/sugar-emulator14
-rw-r--r--shell/bin/sugar-install-bundle20
-rw-r--r--shell/bin/sugar-launch89
-rwxr-xr-xshell/bin/sugar-session274
-rw-r--r--shell/bin/sugar-ui-check161
-rw-r--r--shell/bin/sugar.in76
-rw-r--r--shell/configure.ac84
-rw-r--r--shell/data/.gitignore2
-rw-r--r--shell/data/GPLv2339
-rw-r--r--shell/data/Makefile.am68
-rw-r--r--shell/data/activities.defaults28
-rwxr-xr-xshell/data/em.py3302
-rw-r--r--shell/data/gtkrc.em12
-rw-r--r--shell/data/icons/Makefile.am15
-rw-r--r--shell/data/icons/module-about_me.svg7
-rw-r--r--shell/data/icons/module-about_my_computer.svg6
-rw-r--r--shell/data/icons/module-date_and_time.svg19
-rw-r--r--shell/data/icons/module-frame.svg13
-rw-r--r--shell/data/icons/module-keyboard.svg134
-rw-r--r--shell/data/icons/module-language.svg59
-rw-r--r--shell/data/icons/module-modemconfiguration.svg11
-rw-r--r--shell/data/icons/module-network.svg32
-rw-r--r--shell/data/icons/module-power.svg13
-rw-r--r--shell/data/icons/module-updater.svg16
-rw-r--r--shell/data/kbdconfig3
-rw-r--r--shell/data/mime.defaults24
-rw-r--r--shell/data/nm-user-settings.conf28
-rw-r--r--shell/data/sugar-emulator.desktop.in10
-rw-r--r--shell/data/sugar-xo.svg7
-rw-r--r--shell/data/sugar.desktop6
-rw-r--r--shell/data/sugar.schemas.in347
-rw-r--r--shell/data/sugar.xml.in11
-rw-r--r--shell/docs/GPL-C.txt18
-rw-r--r--shell/docs/GPL-python.txt16
-rw-r--r--shell/docs/LGPL-C.txt18
-rw-r--r--shell/docs/LGPL-python.txt17
-rw-r--r--shell/docs/controls.txt199
-rw-r--r--shell/docs/design.txt126
-rw-r--r--shell/docs/release_howto.txt73
-rw-r--r--shell/extensions/Makefile.am1
-rw-r--r--shell/extensions/cpsection/Makefile.am5
-rw-r--r--shell/extensions/cpsection/__init__.py0
-rw-r--r--shell/extensions/cpsection/aboutcomputer/Makefile.am6
-rw-r--r--shell/extensions/cpsection/aboutcomputer/__init__.py22
-rw-r--r--shell/extensions/cpsection/aboutcomputer/model.py138
-rw-r--r--shell/extensions/cpsection/aboutcomputer/view.py217
-rw-r--r--shell/extensions/cpsection/aboutme/Makefile.am6
-rw-r--r--shell/extensions/cpsection/aboutme/__init__.py28
-rw-r--r--shell/extensions/cpsection/aboutme/model.py115
-rw-r--r--shell/extensions/cpsection/aboutme/view.py340
-rw-r--r--shell/extensions/cpsection/datetime/Makefile.am6
-rw-r--r--shell/extensions/cpsection/datetime/__init__.py21
-rw-r--r--shell/extensions/cpsection/datetime/model.py92
-rw-r--r--shell/extensions/cpsection/datetime/view.py138
-rw-r--r--shell/extensions/cpsection/frame/Makefile.am6
-rw-r--r--shell/extensions/cpsection/frame/__init__.py21
-rw-r--r--shell/extensions/cpsection/frame/model.py63
-rw-r--r--shell/extensions/cpsection/frame/view.py232
-rw-r--r--shell/extensions/cpsection/keyboard/Makefile.am6
-rw-r--r--shell/extensions/cpsection/keyboard/__init__.py22
-rw-r--r--shell/extensions/cpsection/keyboard/model.py169
-rw-r--r--shell/extensions/cpsection/keyboard/view.py426
-rw-r--r--shell/extensions/cpsection/language/Makefile.am6
-rw-r--r--shell/extensions/cpsection/language/__init__.py22
-rw-r--r--shell/extensions/cpsection/language/model.py151
-rw-r--r--shell/extensions/cpsection/language/view.py282
-rw-r--r--shell/extensions/cpsection/modemconfiguration/Makefile.am6
-rw-r--r--shell/extensions/cpsection/modemconfiguration/__init__.py22
-rwxr-xr-xshell/extensions/cpsection/modemconfiguration/model.py70
-rw-r--r--shell/extensions/cpsection/modemconfiguration/view.py250
-rw-r--r--shell/extensions/cpsection/network/Makefile.am6
-rw-r--r--shell/extensions/cpsection/network/__init__.py25
-rw-r--r--shell/extensions/cpsection/network/model.py141
-rw-r--r--shell/extensions/cpsection/network/view.py250
-rw-r--r--shell/extensions/cpsection/power/Makefile.am6
-rw-r--r--shell/extensions/cpsection/power/__init__.py23
-rw-r--r--shell/extensions/cpsection/power/model.py116
-rw-r--r--shell/extensions/cpsection/power/view.py177
-rw-r--r--shell/extensions/cpsection/updater/Makefile.am8
-rw-r--r--shell/extensions/cpsection/updater/__init__.py22
-rw-r--r--shell/extensions/cpsection/updater/backends/Makefile.am5
-rw-r--r--shell/extensions/cpsection/updater/backends/__init__.py16
-rw-r--r--shell/extensions/cpsection/updater/backends/aslo.py161
-rwxr-xr-xshell/extensions/cpsection/updater/model.py346
-rw-r--r--shell/extensions/cpsection/updater/view.py391
-rw-r--r--shell/extensions/deviceicon/Makefile.am9
-rw-r--r--shell/extensions/deviceicon/__init__.py0
-rw-r--r--shell/extensions/deviceicon/battery.py251
-rw-r--r--shell/extensions/deviceicon/network.py1006
-rw-r--r--shell/extensions/deviceicon/speaker.py216
-rw-r--r--shell/extensions/deviceicon/touchpad.py132
-rw-r--r--shell/extensions/deviceicon/volume.py121
-rw-r--r--shell/extensions/globalkey/Makefile.am6
-rw-r--r--shell/extensions/globalkey/__init__.py0
-rw-r--r--shell/extensions/globalkey/screenshot.py100
-rw-r--r--shell/extensions/globalkey/viewsource.py27
-rw-r--r--shell/po/ChangeLog0
-rw-r--r--shell/po/POTFILES.in67
-rw-r--r--shell/po/POTFILES.skip1
-rw-r--r--shell/po/af.po522
-rw-r--r--shell/po/am.po420
-rw-r--r--shell/po/ar.po1549
-rw-r--r--shell/po/ay.po420
-rw-r--r--shell/po/bg.po454
-rw-r--r--shell/po/bi.po764
-rw-r--r--shell/po/bn.po419
-rw-r--r--shell/po/bn_IN.po419
-rw-r--r--shell/po/ca.po438
-rw-r--r--shell/po/cpp.po958
-rw-r--r--shell/po/cs.po764
-rw-r--r--shell/po/da.po1227
-rw-r--r--shell/po/de.po1711
-rw-r--r--shell/po/dz.po420
-rw-r--r--shell/po/el.po777
-rw-r--r--shell/po/en.po420
-rw-r--r--shell/po/es.po1573
-rw-r--r--shell/po/fa.po419
-rw-r--r--shell/po/fa_AF.po419
-rw-r--r--shell/po/ff.po420
-rw-r--r--shell/po/fil.po958
-rw-r--r--shell/po/fr.po1619
-rw-r--r--shell/po/gu.po365
-rw-r--r--shell/po/ha.po447
-rw-r--r--shell/po/he.po764
-rw-r--r--shell/po/hi.po1416
-rw-r--r--shell/po/ht.po583
-rw-r--r--shell/po/hu.po764
-rw-r--r--shell/po/id.po958
-rw-r--r--shell/po/ig.po448
-rw-r--r--shell/po/is.po420
-rw-r--r--shell/po/it.po1668
-rw-r--r--shell/po/ja.po1558
-rw-r--r--shell/po/km.po584
-rw-r--r--shell/po/ko.po420
-rw-r--r--shell/po/kos.po1211
-rw-r--r--shell/po/mg.po1213
-rw-r--r--shell/po/mi.po979
-rw-r--r--shell/po/mk.po432
-rw-r--r--shell/po/ml.po420
-rw-r--r--shell/po/mn.po1516
-rw-r--r--shell/po/mr.po651
-rw-r--r--shell/po/ms.po958
-rw-r--r--shell/po/mvo.po517
-rw-r--r--shell/po/nb.po621
-rw-r--r--shell/po/ne.po1267
-rw-r--r--shell/po/nl.po1556
-rw-r--r--shell/po/pa.po420
-rw-r--r--shell/po/pap.po535
-rw-r--r--shell/po/pis.po517
-rw-r--r--shell/po/pl.po485
-rw-r--r--shell/po/ps.po424
-rw-r--r--shell/po/pseudo.po517
-rw-r--r--shell/po/pt.po1481
-rw-r--r--shell/po/pt_BR.po438
-rw-r--r--shell/po/qu.po420
-rw-r--r--shell/po/ro.po419
-rw-r--r--shell/po/ru.po420
-rw-r--r--shell/po/rw.po596
-rw-r--r--shell/po/sd.po517
-rw-r--r--shell/po/si.po899
-rw-r--r--shell/po/sk.po764
-rw-r--r--shell/po/sl.po1098
-rw-r--r--shell/po/sq.po1215
-rw-r--r--shell/po/sv.po1339
-rw-r--r--shell/po/sw.po1222
-rw-r--r--shell/po/ta.po1260
-rw-r--r--shell/po/te.po763
-rw-r--r--shell/po/th.po420
-rw-r--r--shell/po/tpi.po517
-rw-r--r--shell/po/tr.po839
-rw-r--r--shell/po/tvl.po1188
-rw-r--r--shell/po/tzo.po1210
-rw-r--r--shell/po/ug.po979
-rw-r--r--shell/po/ur.po743
-rw-r--r--shell/po/vi.po1415
-rw-r--r--shell/po/wa.po764
-rw-r--r--shell/po/yo.po448
-rw-r--r--shell/po/zh_CN.po420
-rw-r--r--shell/po/zh_TW.po1543
-rw-r--r--shell/src/Makefile.am1
-rw-r--r--shell/src/jarabe/.gitignore1
-rw-r--r--shell/src/jarabe/Makefile.am16
-rw-r--r--shell/src/jarabe/__init__.py26
-rw-r--r--shell/src/jarabe/config.py.in26
-rw-r--r--shell/src/jarabe/controlpanel/Makefile.am10
-rw-r--r--shell/src/jarabe/controlpanel/__init__.py16
-rw-r--r--shell/src/jarabe/controlpanel/cmd.py158
-rw-r--r--shell/src/jarabe/controlpanel/gui.py431
-rw-r--r--shell/src/jarabe/controlpanel/inlinealert.py83
-rw-r--r--shell/src/jarabe/controlpanel/sectionview.py55
-rw-r--r--shell/src/jarabe/controlpanel/toolbar.py157
-rw-r--r--shell/src/jarabe/desktop/Makefile.am18
-rw-r--r--shell/src/jarabe/desktop/__init__.py16
-rw-r--r--shell/src/jarabe/desktop/activitieslist.py451
-rw-r--r--shell/src/jarabe/desktop/favoriteslayout.py488
-rw-r--r--shell/src/jarabe/desktop/favoritesview.py670
-rw-r--r--shell/src/jarabe/desktop/friendview.py87
-rw-r--r--shell/src/jarabe/desktop/grid.py201
-rw-r--r--shell/src/jarabe/desktop/groupbox.py92
-rw-r--r--shell/src/jarabe/desktop/homebox.py298
-rw-r--r--shell/src/jarabe/desktop/homewindow.py193
-rw-r--r--shell/src/jarabe/desktop/keydialog.py317
-rw-r--r--shell/src/jarabe/desktop/meshbox.py670
-rw-r--r--shell/src/jarabe/desktop/networkviews.py716
-rw-r--r--shell/src/jarabe/desktop/schoolserver.py127
-rw-r--r--shell/src/jarabe/desktop/snowflakelayout.py108
-rw-r--r--shell/src/jarabe/desktop/spreadlayout.py83
-rw-r--r--shell/src/jarabe/desktop/transitionbox.py96
-rw-r--r--shell/src/jarabe/frame/Makefile.am18
-rw-r--r--shell/src/jarabe/frame/__init__.py25
-rw-r--r--shell/src/jarabe/frame/activitiestray.py745
-rw-r--r--shell/src/jarabe/frame/clipboard.py149
-rw-r--r--shell/src/jarabe/frame/clipboardicon.py158
-rw-r--r--shell/src/jarabe/frame/clipboardmenu.py249
-rw-r--r--shell/src/jarabe/frame/clipboardobject.py142
-rw-r--r--shell/src/jarabe/frame/clipboardpanelwindow.py103
-rw-r--r--shell/src/jarabe/frame/clipboardtray.py216
-rw-r--r--shell/src/jarabe/frame/devicestray.py54
-rw-r--r--shell/src/jarabe/frame/eventarea.py151
-rw-r--r--shell/src/jarabe/frame/frame.py351
-rw-r--r--shell/src/jarabe/frame/frameinvoker.py36
-rw-r--r--shell/src/jarabe/frame/framewindow.py117
-rw-r--r--shell/src/jarabe/frame/friendstray.py118
-rw-r--r--shell/src/jarabe/frame/notification.py100
-rw-r--r--shell/src/jarabe/frame/zoomtoolbar.py89
-rw-r--r--shell/src/jarabe/intro/Makefile.am9
-rw-r--r--shell/src/jarabe/intro/__init__.py25
-rw-r--r--shell/src/jarabe/intro/colorpicker.py43
-rw-r--r--shell/src/jarabe/intro/default-picture.pngbin0 -> 10442 bytes
-rw-r--r--shell/src/jarabe/intro/window.py298
-rw-r--r--shell/src/jarabe/journal/Makefile.am17
-rw-r--r--shell/src/jarabe/journal/__init__.py15
-rw-r--r--shell/src/jarabe/journal/detailview.py117
-rw-r--r--shell/src/jarabe/journal/expandedentry.py429
-rw-r--r--shell/src/jarabe/journal/journalactivity.py371
-rw-r--r--shell/src/jarabe/journal/journalentrybundle.py94
-rw-r--r--shell/src/jarabe/journal/journaltoolbox.py458
-rw-r--r--shell/src/jarabe/journal/keepicon.py59
-rw-r--r--shell/src/jarabe/journal/listmodel.py201
-rw-r--r--shell/src/jarabe/journal/listview.py641
-rw-r--r--shell/src/jarabe/journal/misc.py262
-rw-r--r--shell/src/jarabe/journal/modalalert.py97
-rw-r--r--shell/src/jarabe/journal/model.py541
-rw-r--r--shell/src/jarabe/journal/objectchooser.py199
-rw-r--r--shell/src/jarabe/journal/palettes.py235
-rw-r--r--shell/src/jarabe/journal/volumestoolbar.py207
-rw-r--r--shell/src/jarabe/model/Makefile.am19
-rw-r--r--shell/src/jarabe/model/__init__.py16
-rw-r--r--shell/src/jarabe/model/adhoc.py292
-rw-r--r--shell/src/jarabe/model/buddy.py250
-rw-r--r--shell/src/jarabe/model/bundleregistry.py444
-rw-r--r--shell/src/jarabe/model/filetransfer.py374
-rw-r--r--shell/src/jarabe/model/friends.py122
-rw-r--r--shell/src/jarabe/model/invites.py239
-rw-r--r--shell/src/jarabe/model/mimeregistry.py49
-rw-r--r--shell/src/jarabe/model/neighborhood.py863
-rw-r--r--shell/src/jarabe/model/network.py751
-rw-r--r--shell/src/jarabe/model/notifications.py95
-rw-r--r--shell/src/jarabe/model/olpcmesh.py214
-rw-r--r--shell/src/jarabe/model/screen.py43
-rw-r--r--shell/src/jarabe/model/session.py89
-rw-r--r--shell/src/jarabe/model/shell.py641
-rw-r--r--shell/src/jarabe/model/sound.py58
-rw-r--r--shell/src/jarabe/model/telepathyclient.py100
-rw-r--r--shell/src/jarabe/util/Makefile.am7
-rw-r--r--shell/src/jarabe/util/__init__.py19
-rw-r--r--shell/src/jarabe/util/emulator.py177
-rw-r--r--shell/src/jarabe/util/telepathy/Makefile.am4
-rw-r--r--shell/src/jarabe/util/telepathy/__init__.py19
-rw-r--r--shell/src/jarabe/util/telepathy/connection_watcher.py118
-rw-r--r--shell/src/jarabe/view/Makefile.am12
-rw-r--r--shell/src/jarabe/view/__init__.py16
-rw-r--r--shell/src/jarabe/view/buddyicon.py61
-rw-r--r--shell/src/jarabe/view/buddymenu.py168
-rw-r--r--shell/src/jarabe/view/keyhandler.py242
-rw-r--r--shell/src/jarabe/view/launcher.py217
-rw-r--r--shell/src/jarabe/view/palettes.py250
-rw-r--r--shell/src/jarabe/view/pulsingicon.py229
-rw-r--r--shell/src/jarabe/view/service.py89
-rw-r--r--shell/src/jarabe/view/tabbinghandler.py148
-rw-r--r--shell/src/jarabe/view/viewsource.py464
291 files changed, 97471 insertions, 0 deletions
diff --git a/shell/.gitignore b/shell/.gitignore
new file mode 100644
index 0000000..047a849
--- /dev/null
+++ b/shell/.gitignore
@@ -0,0 +1,59 @@
+# Generic
+
+*.pyc
+*~
+Makefile
+Makefile.in
+*.deps
+*.libs
+*.la
+*.o
+*.lo
+*.loT
+.*.sw?
+*.service
+stamp-*
+
+# Absolute
+
+aclocal.m4
+autom4te.cache
+config.h
+config.h.in
+config.log
+config.status
+configure
+compile
+install-sh
+missing
+py-compile
+dbus-installed.conf
+intltool-extract
+intltool-extract.in
+intltool-merge
+intltool-merge.in
+intltool-update
+intltool-update.in
+mkinstalldirs
+po/Makefile.in.in
+po/POTFILES
+po/*.gmo
+po/.intltool-merge-cache
+sugar/__installed__.py
+tools/sugar-setup-activity
+threadframe
+config.guess
+config.sub
+depcomp
+libtool
+ltmain.sh
+m4/intltool.m4
+sugar/browser/_sugarbrowser.c
+browser/sugar-marshal.c
+browser/sugar-marshal.h
+bin/sugar
+shell/extensions/_extensions.c
+data/sugar.gtkrc
+data/sugar.xml
+data/sugar-xo.gtkrc
+data/sugar-emulator.desktop
diff --git a/shell/AUTHORS b/shell/AUTHORS
new file mode 100644
index 0000000..8cd5dac
--- /dev/null
+++ b/shell/AUTHORS
@@ -0,0 +1,14 @@
+Marco Pesenti Gritti <mpg@redhat.com>
+Dan Williams <dcbw@redhat.com>
+Tomeu Vizoso <tomeu@tomeuvizoso.net>
+Dan Winship <dwinship@redhat.com>
+Benjamin Berg <benjamin@sipsolutions.net>
+Eduardo Silva <edsiper@gmail.com>
+Simon Schampijer <simon@schampijer.de>
+Bert Freudenberg <bert@freudenbergs.de>
+Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
+Dafydd Harries <daf@rhydd.org>
+John (J5) Palmieri <johnp@redhat.com>
+Morgan Collett <morgan.collett@gmail.com>
+Simon McVittie <simon.mcvittie@collabora.co.uk>
+Owen Williams <owen@ywwg.com>
diff --git a/shell/COPYING b/shell/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/shell/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/shell/MAINTAINERS b/shell/MAINTAINERS
new file mode 100644
index 0000000..9c63644
--- /dev/null
+++ b/shell/MAINTAINERS
@@ -0,0 +1,9 @@
+== Current maintainers ==
+
+Aleksey Lim <alsroot@member.fsf.org> -- Journal
+Tomeu Vizoso <tomeu@sugarlabs.org>
+
+== Past maintainers ==
+
+Marco Pesenti Gritti <marcopg@sugarlabs.org>
+
diff --git a/shell/Makefile.am b/shell/Makefile.am
new file mode 100644
index 0000000..9e252af
--- /dev/null
+++ b/shell/Makefile.am
@@ -0,0 +1,14 @@
+SUBDIRS = bin data po src extensions
+
+DISTCLEANFILES = \
+ intltool-extract \
+ intltool-merge \
+ intltool-update
+
+EXTRA_DIST = \
+ $(bin_SCRIPTS) \
+ intltool-merge.in \
+ intltool-update.in \
+ intltool-extract.in
+
+DISTCHECK_CONFIGURE_FLAGS = --disable-update-mimedb
diff --git a/shell/README b/shell/README
new file mode 100644
index 0000000..1f89810
--- /dev/null
+++ b/shell/README
@@ -0,0 +1,44 @@
+Building
+========
+
+For details see: http://wiki.sugarlabs.org/go/Development_Team/Jhbuild
+
+Sugar-jhbuild will automatically download the latest of Sugar's
+dependencies as well as Sugar itself directly from their source
+repositories, rather than relying on source packages that may have
+become stale. These are generic instructions on how to use jhbuild
+to get up and running with Sugar.
+
+ $ cd sugar-jhbuild
+ $ ./sugar-jhbuild update
+ $ ./sugar-jhbuild depscheck
+ $ ./sugar-jhbuild buildgit
+
+Running multiple instances on the same machine
+==============================================
+
+You can use the SUGAR_PROFILE command line options.
+For example:
+
+SUGAR_PROFILE=profile-1 sugar
+SUGAR_PROFILE=profile-2 sugar
+...
+
+
+Emulator key bindings
+=====================
+
+F1 Mesh zoom level
+F2 Friends zoom level
+F3 Home zoom level
+F4 Activity zoom level
+
+Alt+f Show the frame
+Alt+r Rotate the screen
+Alt+o Toggle overlay visibility
+Alt+= Open the developer console
+Alt+0 Open the developer console
+Alt+q Quit the emulator
+
+Ctrl+s Activate sketch mode in chat
+
diff --git a/shell/autogen.sh b/shell/autogen.sh
new file mode 100755
index 0000000..a71e202
--- /dev/null
+++ b/shell/autogen.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+intltoolize
+autoreconf -i
+./configure --enable-maintainer-mode "$@"
diff --git a/shell/bin/Makefile.am b/shell/bin/Makefile.am
new file mode 100644
index 0000000..05a9215
--- /dev/null
+++ b/shell/bin/Makefile.am
@@ -0,0 +1,14 @@
+python_scripts = \
+ sugar-activity \
+ sugar-control-panel \
+ sugar-emulator \
+ sugar-install-bundle \
+ sugar-launch \
+ sugar-session \
+ sugar-ui-check
+
+bin_SCRIPTS = \
+ sugar \
+ $(python_scripts)
+
+EXTRA_DIST = $(python_scripts) sugar.in
diff --git a/shell/bin/sugar-activity b/shell/bin/sugar-activity
new file mode 100644
index 0000000..4abdd80
--- /dev/null
+++ b/shell/bin/sugar-activity
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2006-2008, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from sugar.activity import main
+
+main.main()
diff --git a/shell/bin/sugar-control-panel b/shell/bin/sugar-control-panel
new file mode 100644
index 0000000..a97e3c0
--- /dev/null
+++ b/shell/bin/sugar-control-panel
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# Copyright (C) 2008, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+
+from jarabe import config
+
+sys.path.append(config.ext_path)
+
+from jarabe.controlpanel.cmd import main
+
+main()
+
+
diff --git a/shell/bin/sugar-emulator b/shell/bin/sugar-emulator
new file mode 100755
index 0000000..308aac7
--- /dev/null
+++ b/shell/bin/sugar-emulator
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+if [ "$(id -u)" -eq 0 -o "$(id -ru)" -eq 0 ] ; then
+ echo Refusing to run as root.
+ exit 3
+fi
+
+# Source debug definitions
+if [ -f ~/.sugar/debug ]; then
+ . ~/.sugar/debug
+fi
+
+# Start emulator
+python -c "import sys; from jarabe.util import emulator; sys.argv[0]='$0'; emulator.main()" "$@"
diff --git a/shell/bin/sugar-install-bundle b/shell/bin/sugar-install-bundle
new file mode 100644
index 0000000..52deada
--- /dev/null
+++ b/shell/bin/sugar-install-bundle
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+import sys
+
+from sugar.bundle.activitybundle import ActivityBundle
+
+from dbus.mainloop.glib import DBusGMainLoop
+DBusGMainLoop(set_as_default=True)
+
+def cmd_help():
+ print 'Usage: sugar-install-bundle [ bundlename ] \n\n\
+ Install an activity bundle (.xo). \n'
+
+if len(sys.argv) != 2:
+ cmd_help()
+ sys.exit(2)
+
+bundle = ActivityBundle(sys.argv[1])
+bundle.install()
+
+print "%s: '%s' installed." % (sys.argv[0], sys.argv[1])
diff --git a/shell/bin/sugar-launch b/shell/bin/sugar-launch
new file mode 100644
index 0000000..7297a8e
--- /dev/null
+++ b/shell/bin/sugar-launch
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+import dbus
+from optparse import OptionParser
+
+from sugar.activity import activityfactory
+from sugar.bundle.activitybundle import ActivityBundle
+
+usage = "usage: %prog [options] activity"
+parser = OptionParser(usage)
+parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help="launch activity inside gdb")
+(options, args) = parser.parse_args()
+
+if len(args) == 0:
+ print 'You need to specify the activity bundle_id.'
+ sys.exit(1)
+
+bus = dbus.SessionBus()
+proxy = bus.get_object('org.laptop.Shell', '/org/laptop/Shell')
+path = dbus.Interface(proxy, 'org.laptop.Shell').GetBundlePath(args[0])
+if not path:
+ print 'Cannot find %s bundle.' % args[0]
+ sys.exit(1)
+
+activity = ActivityBundle(path)
+cmd_args = activityfactory.get_command(activity)
+
+def _which(exec_file):
+ if 'PATH' in os.environ:
+ envpath = os.environ['PATH']
+ else:
+ return None
+
+ for path in envpath.split(os.pathsep):
+ fullname = os.path.join(path, exec_file)
+ if os.path.exists(fullname):
+ return fullname
+
+ return None
+
+def _get_interpreter(exec_file):
+ if os.path.exists(exec_file):
+ abs_path = exec_file
+ else:
+ abs_path = _which(exec_file)
+ if not abs_path:
+ return exec_file
+
+ f = open(abs_path)
+ line = f.readline(100)
+ if line.startswith('#!'):
+ cmds = line[2:].strip().split(' ')
+ cmds.append(abs_path)
+
+ if '/usr/bin/env' in cmds:
+ cmds.remove('/usr/bin/env')
+
+ return cmds
+
+ return exec_file
+
+if options.debug:
+ act_args = cmd_args
+ cmd_args = ['gdb', '--args']
+ cmd_args.extend(_get_interpreter(act_args.pop(0)))
+ cmd_args.extend(act_args)
+
+os.chdir(str(activity.get_path()))
+os.execvpe(cmd_args[0], cmd_args, activityfactory.get_environment(activity))
+
diff --git a/shell/bin/sugar-session b/shell/bin/sugar-session
new file mode 100755
index 0000000..b1f0086
--- /dev/null
+++ b/shell/bin/sugar-session
@@ -0,0 +1,274 @@
+#!/usr/bin/env python
+# Copyright (C) 2006, Red Hat, Inc.
+# Copyright (C) 2009, One Laptop Per Child Association Inc
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+import time
+import subprocess
+import shutil
+
+if os.environ.get('SUGAR_LOGGER_LEVEL', '') == 'debug':
+ print '%r STARTUP: Starting the shell' % time.time()
+ sys.stdout.flush()
+
+import gettext
+import logging
+
+import gconf
+import gtk
+import gobject
+import dbus.glib
+import wnck
+
+try:
+ import xklavier
+except ImportError:
+ logging.debug('Could not load xklavier for keyboard configuration')
+
+gtk.gdk.threads_init()
+dbus.glib.threads_init()
+
+def cleanup_logs(logs_dir):
+ """Clean up the log directory, moving old logs into a numbered backup
+ directory. We only keep `_MAX_BACKUP_DIRS` of these backup directories
+ around; the rest are removed."""
+ if not os.path.isdir(logs_dir):
+ os.makedirs(logs_dir)
+
+ backup_logs = []
+ backup_dirs = []
+ for f in os.listdir(logs_dir):
+ path = os.path.join(logs_dir, f)
+ if os.path.isfile(path):
+ backup_logs.append(f)
+ elif os.path.isdir(path):
+ backup_dirs.append(path)
+
+ if len(backup_dirs) > 3:
+ backup_dirs.sort()
+ root = backup_dirs[0]
+ for f in os.listdir(root):
+ os.remove(os.path.join(root, f))
+ os.rmdir(root)
+
+ if len(backup_logs) > 0:
+ name = str(int(time.time()))
+ backup_dir = os.path.join(logs_dir, name)
+ os.mkdir(backup_dir)
+ for log in backup_logs:
+ source_path = os.path.join(logs_dir, log)
+ dest_path = os.path.join(backup_dir, log)
+ os.rename(source_path, dest_path)
+
+def start_ui_service():
+ from jarabe.view.service import UIService
+
+ ui_service = UIService()
+
+def start_session_manager():
+ from jarabe.model.session import get_session_manager
+
+ session_manager = get_session_manager()
+ session_manager.start()
+
+def unfreeze_dcon_cb():
+ logging.debug('STARTUP: unfreeze_dcon_cb')
+ from jarabe.model import screen
+
+ screen.set_dcon_freeze(0)
+
+def setup_frame_cb():
+ logging.debug('STARTUP: setup_frame_cb')
+ from jarabe import frame
+ frame.get_view()
+
+def setup_keyhandler_cb():
+ logging.debug('STARTUP: setup_keyhandler_cb')
+ from jarabe.view import keyhandler
+ from jarabe import frame
+ keyhandler.setup(frame.get_view())
+
+def setup_journal_cb():
+ logging.debug('STARTUP: setup_journal_cb')
+ from jarabe.journal import journalactivity
+ journalactivity.start()
+
+def show_software_updates_cb():
+ logging.debug('STARTUP: show_software_updates_cb')
+ if os.path.isfile(os.path.expanduser('~/.sugar-update')):
+ from jarabe.desktop import homewindow
+ home_window = homewindow.get_instance()
+ home_window.get_home_box().show_software_updates_alert()
+
+def setup_notification_service_cb():
+ from jarabe.model import notifications
+ notifications.init()
+
+def setup_file_transfer_cb():
+ from jarabe.model import filetransfer
+ filetransfer.init()
+
+def setup_keyboard_cb():
+ logging.debug('STARTUP: setup_keyboard_cb')
+
+ gconf_client = gconf.client_get_default()
+
+ try:
+ display = gtk.gdk.display_get_default()
+ if display is not None:
+ engine = xklavier.Engine(display)
+ else:
+ logging.debug('setup_keyboard_cb: Could not get default display.')
+ return
+
+ configrec = xklavier.ConfigRec()
+ configrec.get_from_server(engine)
+
+ layouts = gconf_client.get_list(\
+ '/desktop/sugar/peripherals/keyboard/layouts', gconf.VALUE_STRING)
+ layouts_list = []
+ variants_list = []
+ for layout in layouts:
+ layouts_list.append(layout.split('(')[0])
+ variants_list.append(layout.split('(')[1][:-1])
+
+ if layouts_list is not None and layouts_list is not [] \
+ and variants_list is not None and variants_list is not []:
+ configrec.set_layouts(layouts_list)
+ configrec.set_variants(variants_list)
+
+ model = gconf_client.get_string(\
+ '/desktop/sugar/peripherals/keyboard/model')
+ if model:
+ configrec.set_model(model)
+
+ options = gconf_client.get_list(\
+ '/desktop/sugar/peripherals/keyboard/options', gconf.VALUE_STRING)
+ if options is not [] and options is not None:
+ configrec.set_options(options)
+
+ configrec.activate(engine)
+ except Exception:
+ logging.exception('Error during keyboard configuration')
+
+def setup_window_manager():
+ logging.debug('STARTUP: window_manager')
+
+ # have to reset cursor(metacity sets it on startup)
+ if subprocess.call('echo $DISPLAY; xsetroot -cursor_name left_ptr', shell=True):
+ logging.warning('Can not reset cursor')
+
+ if subprocess.call('metacity-message disable-keybindings',
+ shell=True):
+ logging.warning('Can not disable metacity keybindings')
+
+def bootstrap():
+ setup_window_manager()
+
+ from jarabe.view import launcher
+ launcher.setup()
+
+ gobject.idle_add(setup_frame_cb)
+ gobject.idle_add(setup_keyhandler_cb)
+ gobject.idle_add(setup_journal_cb)
+ gobject.idle_add(setup_notification_service_cb)
+ gobject.idle_add(setup_file_transfer_cb)
+ gobject.idle_add(show_software_updates_cb)
+
+ if sys.modules.has_key('xklavier'):
+ gobject.idle_add(setup_keyboard_cb)
+
+def set_fonts():
+ client = gconf.client_get_default()
+ face = client.get_string('/desktop/sugar/font/default_face')
+ size = client.get_float('/desktop/sugar/font/default_size')
+ settings = gtk.settings_get_default()
+ settings.set_property("gtk-font-name", "%s %f" % (face, size))
+
+def main():
+ try:
+ from sugar import env
+ # Remove temporary files. See http://bugs.sugarlabs.org/ticket/1876
+ data_dir = os.path.join(env.get_profile_path(), 'data')
+ shutil.rmtree(data_dir, ignore_errors=True)
+ os.makedirs(data_dir)
+ cleanup_logs(env.get_logs_path())
+ except OSError, e:
+ # logs cleanup is not critical; it should not prevent sugar from
+ # starting if (for example) the disk is full or read-only.
+ print 'logs cleanup failed: %s' % e
+
+ from sugar import logger
+ # NOTE: This needs to happen so early because some modules register translatable
+ # strings in the module scope.
+ from jarabe import config
+ gettext.bindtextdomain('sugar', config.locale_path)
+ gettext.bindtextdomain('sugar-toolkit', config.locale_path)
+ gettext.textdomain('sugar')
+
+ from jarabe.desktop import homewindow
+ from jarabe.model import sound
+ from jarabe import intro
+
+ logger.start('shell')
+
+ client = gconf.client_get_default()
+ client.set_string('/apps/metacity/general/mouse_button_modifier',
+ 'disabled')
+
+ timezone = client.get_string('/desktop/sugar/date/timezone')
+ if timezone is not None and timezone:
+ os.environ['TZ'] = timezone
+
+ set_fonts()
+
+ # this must be added early, so that it executes and unfreezes the screen
+ # even when we initially get blocked on the intro screen
+ gobject.idle_add(unfreeze_dcon_cb)
+
+ intro.check_profile()
+
+ start_ui_service()
+ start_session_manager()
+
+ sound.restore()
+
+ sys.path.append(config.ext_path)
+
+ icons_path = os.path.join(config.data_path, 'icons')
+ gtk.icon_theme_get_default().append_search_path(icons_path)
+
+ # open homewindow before window_manager to let desktop appear fast
+ home_window = homewindow.get_instance()
+ home_window.show()
+
+ screen = wnck.screen_get_default()
+ screen.connect('window-manager-changed', __window_manager_changed_cb)
+
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
+
+def __window_manager_changed_cb(screen):
+ wm_name = screen.get_window_manager_name()
+ if wm_name is not None:
+ screen.disconnect_by_func(__window_manager_changed_cb)
+ bootstrap()
+
+main()
diff --git a/shell/bin/sugar-ui-check b/shell/bin/sugar-ui-check
new file mode 100644
index 0000000..4d71796
--- /dev/null
+++ b/shell/bin/sugar-ui-check
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+# Copyright (C) 2008, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import os
+import sys
+import subprocess
+import time
+
+import dbus
+import gobject
+import gtk
+import wnck
+
+from sugar import wm
+
+from jarabe.model.shell import get_sugar_window_type
+from sugar.bundle.activitybundle import ActivityBundle
+from jarabe import config
+
+checks_queue = []
+checks_failed = []
+checks_succeeded = []
+
+def get_dbus_version():
+ p = subprocess.Popen(['dbus-daemon', '--version'], stdout=subprocess.PIPE)
+
+ output = p.communicate()[0]
+ first_line = output.split('\n')[0]
+
+ return first_line.split(' ')[-1]
+
+class Check(object):
+ def __init__(self):
+ self.name = None
+ self.succeeded = False
+ self.start_time = None
+ self.max_time = None
+ self.timeout = None
+
+ def start(self):
+ logging.info('Start %s check.' % self.name)
+
+ self.start_time = time.time()
+
+ def get_failed(self):
+ if self.max_time and self.start_time:
+ if time.time() - self.start_time > self.max_time:
+ return True
+ return False
+
+ failed = property(get_failed)
+
+class ShellCheck(Check):
+ def __init__(self):
+ Check.__init__(self)
+
+ self.name = 'Shell'
+ self.max_time = 30
+
+ def start(self):
+ Check.start(self)
+
+ screen = wnck.screen_get_default()
+ screen.connect('window-opened', self._window_opened_cb)
+
+ def _window_opened_cb(self, screen, window):
+ if window.get_window_type() == wnck.WINDOW_DESKTOP:
+ self.succeeded = True
+
+class ActivityCheck(Check):
+ def __init__(self, bundle_id):
+ Check.__init__(self)
+
+ self.name = bundle_id
+ self.max_time = 120
+
+ def start(self):
+ Check.start(self)
+
+ self.launch_activity()
+
+ screen = wnck.screen_get_default()
+ screen.connect('window-opened', self._window_opened_cb)
+
+ def launch_activity(self):
+ from sugar.activity import activityfactory
+
+ bus = dbus.SessionBus()
+ proxy = bus.get_object('org.laptop.Shell', '/org/laptop/Shell')
+ iface = dbus.Interface(proxy, 'org.laptop.Shell')
+ path = iface.GetBundlePath(self.name)
+
+ if path:
+ activityfactory.create(ActivityBundle(path))
+ else:
+ logging.error('Cannot find activity %s.' % self.name)
+
+ def _window_opened_cb(self, screen, window):
+ if wm.get_bundle_id(window) == self.name and \
+ get_sugar_window_type(window) != 'launcher':
+ self.succeeded = True
+
+def _timeout_cb():
+ check = checks_queue[0]
+ if check.failed:
+ logging.info('%s check failed.' % (check.name))
+ checks_failed.append(checks_queue.pop(0))
+ elif check.succeeded:
+ logging.info('%s check succeeded.' % (check.name))
+ checks_succeeded.append(checks_queue.pop(0))
+ else:
+ return True
+
+ if len(checks_queue) > 0:
+ checks_queue[0].start()
+ else:
+ gtk.main_quit()
+
+ return True
+
+def main():
+ os.environ['GTK2_RC_FILES'] = os.path.join(config.data_path, 'sugar-100.gtkrc')
+
+ logging.basicConfig(level=logging.INFO,
+ format='%(asctime)s %(levelname)s %(message)s')
+
+ checks_queue.append(ShellCheck())
+
+ if get_dbus_version() >= '1.2.1':
+ # FIXME needs to get a list of the installed activities
+ checks_queue.append(ActivityCheck('org.laptop.Log'))
+ checks_queue.append(ActivityCheck('org.laptop.Chat'))
+ checks_queue.append(ActivityCheck('org.laptop.WebActivity'))
+ checks_queue.append(ActivityCheck('org.laptop.Pippy'))
+ checks_queue.append(ActivityCheck('org.laptop.Terminal'))
+ checks_queue.append(ActivityCheck('org.laptop.AbiWordActivity'))
+
+ checks_queue[0].start()
+ gobject.timeout_add(500, _timeout_cb)
+
+ gtk.main()
+
+ if len(checks_failed) > 0:
+ sys.exit(1)
+
+main()
diff --git a/shell/bin/sugar.in b/shell/bin/sugar.in
new file mode 100644
index 0000000..2df0ab8
--- /dev/null
+++ b/shell/bin/sugar.in
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+if [ "$(id -u)" -eq 0 -o "$(id -ru)" -eq 0 ] ; then
+ echo Refusing to run as root.
+ exit 3
+fi
+
+usage() {
+ cat <<EOF
+Usage: sugar [OPTION]..
+
+Start Sugar window manager.
+
+Optional arguments.
+ -d, --display DISPLAY Display to start sugar
+ -s, --scaling SCALING Scale Sugar theme
+ Supported values: 72, 100
+EOF
+ exit 0
+}
+
+while [ $# -ne 0 ] ; do
+ case "$1" in
+ -d | --display)
+ shift
+ export DISPLAY="$1"
+ ;;
+ -s | --scaling)
+ shift
+ export SUGAR_SCALING="$1"
+ ;;
+ -h | --help)
+ usage
+ ;;
+ esac
+ shift
+done
+
+# Set default profile dir
+if test -z "$SUGAR_PROFILE"; then
+ export SUGAR_PROFILE=default
+fi
+
+if test -z "$SUGAR_SCALING"; then
+ export SUGAR_SCALING=72
+fi
+
+export GTK2_RC_FILES="@prefix@/share/sugar/data/sugar-$SUGAR_SCALING.gtkrc"
+
+# Needed for executing wpa_passphrase
+export PATH="$PATH":/sbin:/usr/sbin
+
+if ! test -f "$GTK2_RC_FILES"; then
+ echo "sugar: ERROR: Gtk theme for scaling $SUGAR_SCALING not available in path $GTK2_RC_FILES"
+ exit 1
+fi
+
+# Set default language
+export LANG="${LANG:-en_US.utf8}"
+export LANGUAGE="${LANGUAGE:-${LANG}}"
+
+# Set Sugar's telepathy accounts directory
+export MC_ACCOUNT_DIR=$HOME/.sugar/$SUGAR_PROFILE/accounts
+
+# Source language settings and debug definitions
+if [ -f ~/.i18n ]; then
+ . ~/.i18n
+fi
+if [ -f ~/.sugar/debug ]; then
+ . ~/.sugar/debug
+fi
+
+echo Xcursor.theme: sugar | xrdb -merge
+metacity --no-force-fullscreen -d $DISPLAY &
+
+exec sugar-session
diff --git a/shell/configure.ac b/shell/configure.ac
new file mode 100644
index 0000000..238aacd
--- /dev/null
+++ b/shell/configure.ac
@@ -0,0 +1,84 @@
+AC_INIT([Sugar],[0.89.3],[],[sugar])
+
+AC_PREREQ([2.59])
+
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_SRCDIR([configure.ac])
+
+SUCROSE_VERSION="0.89.3"
+AC_SUBST(SUCROSE_VERSION)
+
+AM_INIT_AUTOMAKE([1.9 foreign dist-bzip2 no-dist-gzip])
+
+AM_MAINTAINER_MODE
+
+AM_PATH_PYTHON
+
+PKG_CHECK_MODULES(SHELL, pygtk-2.0 gtk+-2.0 gconf-2.0)
+
+# Setup GETTEXT
+#
+ALL_LINGUAS="af am ar ay bg bi bn_IN bn ca cpp cs da de dz el en es fa_AF fa ff fil fr gu ha he hi ht hu id ig is it ja km ko kos mg mi mk ml mn mr ms mvo nb ne nl pa pap pis pl ps pt_BR pt qu ro ru rw sd si sk sl sq sv sw ta te th tpi tr tvl tzo ug ur vi wa yo zh_CN zh_TW"
+
+GETTEXT_PACKAGE=sugar
+AC_PROG_INTLTOOL([0.33])
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package])
+AM_GLIB_GNU_GETTEXT
+
+AC_ARG_ENABLE(update-mimedb,
+ AC_HELP_STRING([--disable-update-mimedb],
+ [disable the update-mime-database after install [default=no]]),,
+ enable_update_mimedb=yes)
+AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes)
+
+# Verify that gconftool is installed
+#
+AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
+
+if test "$GCONFTOOL" = no; then
+ AC_MSG_ERROR([gconftool-2 executable not found in your path - should be installed with GConf])
+fi
+
+AM_GCONF_SOURCE_2
+
+
+AC_CONFIG_FILES([
+bin/Makefile
+bin/sugar
+data/icons/Makefile
+data/Makefile
+data/sugar-emulator.desktop
+extensions/cpsection/aboutcomputer/Makefile
+extensions/cpsection/aboutme/Makefile
+extensions/cpsection/datetime/Makefile
+extensions/cpsection/frame/Makefile
+extensions/cpsection/keyboard/Makefile
+extensions/cpsection/language/Makefile
+extensions/cpsection/modemconfiguration/Makefile
+extensions/cpsection/Makefile
+extensions/cpsection/network/Makefile
+extensions/cpsection/power/Makefile
+extensions/cpsection/updater/backends/Makefile
+extensions/cpsection/updater/Makefile
+extensions/deviceicon/Makefile
+extensions/globalkey/Makefile
+extensions/Makefile
+Makefile
+po/Makefile.in
+src/jarabe/config.py
+src/jarabe/controlpanel/Makefile
+src/jarabe/desktop/Makefile
+src/jarabe/frame/Makefile
+src/jarabe/intro/Makefile
+src/jarabe/journal/Makefile
+src/jarabe/Makefile
+src/jarabe/model/Makefile
+src/jarabe/util/Makefile
+src/jarabe/util/telepathy/Makefile
+src/jarabe/view/Makefile
+src/Makefile
+])
+
+AC_OUTPUT
+
diff --git a/shell/data/.gitignore b/shell/data/.gitignore
new file mode 100644
index 0000000..8263f12
--- /dev/null
+++ b/shell/data/.gitignore
@@ -0,0 +1,2 @@
+*.gtkrc
+sugar.schemas
diff --git a/shell/data/GPLv2 b/shell/data/GPLv2
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/shell/data/GPLv2
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/shell/data/Makefile.am b/shell/data/Makefile.am
new file mode 100644
index 0000000..6a62d23
--- /dev/null
+++ b/shell/data/Makefile.am
@@ -0,0 +1,68 @@
+SUBDIRS = icons
+
+sugar-72.gtkrc: gtkrc.em
+ $(srcdir)/em.py -D scaling=\'72\' $(srcdir)/gtkrc.em > \
+ $(top_builddir)/data/sugar-72.gtkrc
+
+sugar-100.gtkrc: gtkrc.em
+ $(srcdir)/em.py -D scaling=\'100\' $(srcdir)/gtkrc.em > \
+ $(top_builddir)/data/sugar-100.gtkrc
+
+sugardir = $(pkgdatadir)/data
+sugar_DATA = \
+ activities.defaults \
+ kbdconfig \
+ mime.defaults \
+ GPLv2 \
+ $(GTKRC_FILES)
+
+GTKRC_FILES = \
+ sugar-72.gtkrc \
+ sugar-100.gtkrc
+
+xsessionsdir = $(datadir)/xsessions
+xsessions_DATA = sugar.desktop
+
+applicationsdir = $(datadir)/applications
+applications_DATA = sugar-emulator.desktop
+
+mime_xml_in_files = sugar.xml.in
+mime_xml_files = $(mime_xml_in_files:.xml.in=.xml)
+@INTLTOOL_XML_RULE@
+
+mimedir = $(datadir)/mime/packages
+mime_DATA = $(mime_xml_files)
+
+nmservicedir = $(sysconfdir)/dbus-1/system.d/
+nmservice_DATA = nm-user-settings.conf
+
+install-data-hook:
+if ENABLE_UPDATE_MIMEDB
+ if [ -z "$$DESTDIR" ]; then \
+ update-mime-database "$(datadir)/mime"; \
+ fi
+endif
+
+uninstall-hook:
+if ENABLE_UPDATE_MIMEDB
+ if [ -z "$$DESTDIR" ]; then \
+ update-mime-database "$(datadir)/mime"; \
+ fi
+endif
+
+@INTLTOOL_SCHEMAS_RULE@
+
+schemadir = $(GCONF_SCHEMA_FILE_DIR)
+schema_in_files = sugar.schemas.in
+schema_DATA = $(schema_in_files:.schemas.in=.schemas)
+
+install-data-local: $(schema_DATA)
+if GCONF_SCHEMAS_INSTALL
+ GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule sugar.schemas 2>&1 > /dev/null
+endif
+
+icondir = $(datadir)/icons/hicolor/scalable/apps
+icon_DATA = sugar-xo.svg
+
+EXTRA_DIST = $(sugar_DATA) $(xsessions_DATA) $(nmservice_DATA) $(mime_xml_in_files) em.py gtkrc.em $(schema_in_files) $(icon_DATA)
+CLEANFILES = $(GTKRC_FILES) $(mime_xml_files) $(schema_DATA)
diff --git a/shell/data/activities.defaults b/shell/data/activities.defaults
new file mode 100644
index 0000000..c294b99
--- /dev/null
+++ b/shell/data/activities.defaults
@@ -0,0 +1,28 @@
+# Activities to be automatically added to the ring after an upgrade
+
+com.garycmartin.Moon
+com.jotaro.ImplodeActivity
+com.laptop.Ruler
+edu.mit.media.ScratchActivity
+org.laptop.AbiWordActivity
+org.laptop.AcousticMeasure
+org.laptop.Analyze
+org.laptop.Calculate
+org.laptop.Chat
+org.laptop.HelpActivity
+org.laptop.MeasureActivity
+org.laptop.Memorize
+org.laptop.Oficina
+org.laptop.Pippy
+org.laptop.RecordActivity
+org.laptop.TamTamEdit
+org.laptop.TamTamJam
+org.laptop.TamTamMini
+org.laptop.TamTamSynthLab
+org.laptop.TurtleArtActivity
+org.laptop.WebActivity
+org.laptop.WikipediaActivityEN
+org.laptop.sugar.ReadActivity
+org.vpri.EtoysActivity
+vu.lux.olpc.Maze
+vu.lux.olpc.Speak
diff --git a/shell/data/em.py b/shell/data/em.py
new file mode 100755
index 0000000..165d29e
--- /dev/null
+++ b/shell/data/em.py
@@ -0,0 +1,3302 @@
+#!/usr/bin/env python
+#
+# $Id: //projects/empy/em.py#146 $ $Date: 2003/10/27 $
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""
+A system for processing Python as markup embedded in text.
+"""
+
+
+__program__ = 'empy'
+__version__ = '3.3'
+__url__ = 'http://www.alcyone.com/software/empy/'
+__author__ = 'Erik Max Francis <max@alcyone.com>'
+__copyright__ = 'Copyright (C) 2002-2003 Erik Max Francis'
+__license__ = 'LGPL'
+
+
+import copy
+import getopt
+import os
+import re
+import string
+import sys
+import types
+
+try:
+ # The equivalent of import cStringIO as StringIO.
+ import cStringIO
+ StringIO = cStringIO
+ del cStringIO
+except ImportError:
+ import StringIO
+
+# For backward compatibility, we can't assume these are defined.
+False, True = 0, 1
+
+# Some basic defaults.
+FAILURE_CODE = 1
+DEFAULT_PREFIX = '@'
+DEFAULT_PSEUDOMODULE_NAME = 'empy'
+DEFAULT_SCRIPT_NAME = '?'
+SIGNIFICATOR_RE_SUFFIX = r"%(\S+)\s*(.*)\s*$"
+SIGNIFICATOR_RE_STRING = DEFAULT_PREFIX + SIGNIFICATOR_RE_SUFFIX
+BANGPATH = '#!'
+DEFAULT_CHUNK_SIZE = 8192
+DEFAULT_ERRORS = 'strict'
+
+# Character information.
+IDENTIFIER_FIRST_CHARS = '_abcdefghijklmnopqrstuvwxyz' \
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+IDENTIFIER_CHARS = IDENTIFIER_FIRST_CHARS + '0123456789.'
+ENDING_CHARS = {'(': ')', '[': ']', '{': '}'}
+
+# Environment variable names.
+OPTIONS_ENV = 'EMPY_OPTIONS'
+PREFIX_ENV = 'EMPY_PREFIX'
+PSEUDO_ENV = 'EMPY_PSEUDO'
+FLATTEN_ENV = 'EMPY_FLATTEN'
+RAW_ENV = 'EMPY_RAW_ERRORS'
+INTERACTIVE_ENV = 'EMPY_INTERACTIVE'
+BUFFERED_ENV = 'EMPY_BUFFERED_OUTPUT'
+NO_OVERRIDE_ENV = 'EMPY_NO_OVERRIDE'
+UNICODE_ENV = 'EMPY_UNICODE'
+INPUT_ENCODING_ENV = 'EMPY_UNICODE_INPUT_ENCODING'
+OUTPUT_ENCODING_ENV = 'EMPY_UNICODE_OUTPUT_ENCODING'
+INPUT_ERRORS_ENV = 'EMPY_UNICODE_INPUT_ERRORS'
+OUTPUT_ERRORS_ENV = 'EMPY_UNICODE_OUTPUT_ERRORS'
+
+# Interpreter options.
+BANGPATH_OPT = 'processBangpaths' # process bangpaths as comments?
+BUFFERED_OPT = 'bufferedOutput' # fully buffered output?
+RAW_OPT = 'rawErrors' # raw errors?
+EXIT_OPT = 'exitOnError' # exit on error?
+FLATTEN_OPT = 'flatten' # flatten pseudomodule namespace?
+OVERRIDE_OPT = 'override' # override sys.stdout with proxy?
+CALLBACK_OPT = 'noCallbackError' # is no custom callback an error?
+
+# Usage info.
+OPTION_INFO = [
+("-V --version", "Print version and exit"),
+("-h --help", "Print usage and exit"),
+("-H --extended-help", "Print extended usage and exit"),
+("-k --suppress-errors", "Do not exit on errors; go interactive"),
+("-p --prefix=<char>", "Change prefix to something other than @"),
+(" --no-prefix", "Do not do any markup processing at all"),
+("-m --module=<name>", "Change the internal pseudomodule name"),
+("-f --flatten", "Flatten the members of pseudmodule to start"),
+("-r --raw-errors", "Show raw Python errors"),
+("-i --interactive", "Go into interactive mode after processing"),
+("-n --no-override-stdout", "Do not override sys.stdout with proxy"),
+("-o --output=<filename>", "Specify file for output as write"),
+("-a --append=<filename>", "Specify file for output as append"),
+("-b --buffered-output", "Fully buffer output including open"),
+(" --binary", "Treat the file as a binary"),
+(" --chunk-size=<chunk>", "Use this chunk size for reading binaries"),
+("-P --preprocess=<filename>", "Interpret EmPy file before main processing"),
+("-I --import=<modules>", "Import Python modules before processing"),
+("-D --define=<definition>", "Execute Python assignment statement"),
+("-E --execute=<statement>", "Execute Python statement before processing"),
+("-F --execute-file=<filename>", "Execute Python file before processing"),
+(" --pause-at-end", "Prompt at the ending of processing"),
+(" --relative-path", "Add path of EmPy script to sys.path"),
+(" --no-callback-error", "Custom markup without callback is error"),
+(" --no-bangpath-processing", "Suppress bangpaths as comments"),
+("-u --unicode", "Enable Unicode subsystem (Python 2+ only)"),
+(" --unicode-encoding=<e>", "Set both input and output encodings"),
+(" --unicode-input-encoding=<e>", "Set input encoding"),
+(" --unicode-output-encoding=<e>", "Set output encoding"),
+(" --unicode-errors=<E>", "Set both input and output error handler"),
+(" --unicode-input-errors=<E>", "Set input error handler"),
+(" --unicode-output-errors=<E>", "Set output error handler"),
+]
+
+USAGE_NOTES = """\
+Notes: Whitespace immediately inside parentheses of @(...) are
+ignored. Whitespace immediately inside braces of @{...} are ignored,
+unless ... spans multiple lines. Use @{ ... }@ to suppress newline
+following expansion. Simple expressions ignore trailing dots; `@x.'
+means `@(x).'. A #! at the start of a file is treated as a @#
+comment."""
+
+MARKUP_INFO = [
+("@# ... NL", "Comment; remove everything up to newline"),
+("@? NAME NL", "Set the current context name"),
+("@! INTEGER NL", "Set the current context line number"),
+("@ WHITESPACE", "Remove following whitespace; line continuation"),
+("@\\ ESCAPE_CODE", "A C-style escape sequence"),
+("@@", "Literal @; @ is escaped (duplicated prefix)"),
+("@), @], @}", "Literal close parenthesis, bracket, brace"),
+("@ STRING_LITERAL", "Replace with string literal contents"),
+("@( EXPRESSION )", "Evaluate expression and substitute with str"),
+("@( TEST [? THEN [! ELSE]] )", "If test is true, evaluate then, otherwise else"),
+("@( TRY $ CATCH )", "Expand try expression, or catch if it raises"),
+("@ SIMPLE_EXPRESSION", "Evaluate simple expression and substitute;\n"
+ "e.g., @x, @x.y, @f(a, b), @l[i], etc."),
+("@` EXPRESSION `", "Evaluate expression and substitute with repr"),
+("@: EXPRESSION : [DUMMY] :", "Evaluates to @:...:expansion:"),
+("@{ STATEMENTS }", "Statements are executed for side effects"),
+("@[ CONTROL ]", "Control markups: if E; elif E; for N in E;\n"
+ "while E; try; except E, N; finally; continue;\n"
+ "break; end X"),
+("@%% KEY WHITESPACE VALUE NL", "Significator form of __KEY__ = VALUE"),
+("@< CONTENTS >", "Custom markup; meaning provided by user"),
+]
+
+ESCAPE_INFO = [
+("@\\0", "NUL, null"),
+("@\\a", "BEL, bell"),
+("@\\b", "BS, backspace"),
+("@\\dDDD", "three-digit decimal code DDD"),
+("@\\e", "ESC, escape"),
+("@\\f", "FF, form feed"),
+("@\\h", "DEL, delete"),
+("@\\n", "LF, linefeed, newline"),
+("@\\N{NAME}", "Unicode character named NAME"),
+("@\\oOOO", "three-digit octal code OOO"),
+("@\\qQQQQ", "four-digit quaternary code QQQQ"),
+("@\\r", "CR, carriage return"),
+("@\\s", "SP, space"),
+("@\\t", "HT, horizontal tab"),
+("@\\uHHHH", "16-bit hexadecimal Unicode HHHH"),
+("@\\UHHHHHHHH", "32-bit hexadecimal Unicode HHHHHHHH"),
+("@\\v", "VT, vertical tab"),
+("@\\xHH", "two-digit hexadecimal code HH"),
+("@\\z", "EOT, end of transmission"),
+]
+
+PSEUDOMODULE_INFO = [
+("VERSION", "String representing EmPy version"),
+("SIGNIFICATOR_RE_STRING", "Regular expression matching significators"),
+("SIGNIFICATOR_RE_SUFFIX", "The above stub, lacking the prefix"),
+("interpreter", "Currently-executing interpreter instance"),
+("argv", "The EmPy script name and command line arguments"),
+("args", "The command line arguments only"),
+("identify()", "Identify top context as name, line"),
+("setContextName(name)", "Set the name of the current context"),
+("setContextLine(line)", "Set the line number of the current context"),
+("atExit(callable)", "Invoke no-argument function at shutdown"),
+("getGlobals()", "Retrieve this interpreter's globals"),
+("setGlobals(dict)", "Set this interpreter's globals"),
+("updateGlobals(dict)", "Merge dictionary into interpreter's globals"),
+("clearGlobals()", "Start globals over anew"),
+("saveGlobals([deep])", "Save a copy of the globals"),
+("restoreGlobals([pop])", "Restore the most recently saved globals"),
+("defined(name, [loc])", "Find if the name is defined"),
+("evaluate(expression, [loc])", "Evaluate the expression"),
+("serialize(expression, [loc])", "Evaluate and serialize the expression"),
+("execute(statements, [loc])", "Execute the statements"),
+("single(source, [loc])", "Execute the 'single' object"),
+("atomic(name, value, [loc])", "Perform an atomic assignment"),
+("assign(name, value, [loc])", "Perform an arbitrary assignment"),
+("significate(key, [value])", "Significate the given key, value pair"),
+("include(file, [loc])", "Include filename or file-like object"),
+("expand(string, [loc])", "Explicitly expand string and return"),
+("string(data, [name], [loc])", "Process string-like object"),
+("quote(string)", "Quote prefixes in provided string and return"),
+("flatten([keys])", "Flatten module contents into globals namespace"),
+("getPrefix()", "Get current prefix"),
+("setPrefix(char)", "Set new prefix"),
+("stopDiverting()", "Stop diverting; data sent directly to output"),
+("createDiversion(name)", "Create a diversion but do not divert to it"),
+("retrieveDiversion(name)", "Retrieve the actual named diversion object"),
+("startDiversion(name)", "Start diverting to given diversion"),
+("playDiversion(name)", "Recall diversion and then eliminate it"),
+("replayDiversion(name)", "Recall diversion but retain it"),
+("purgeDiversion(name)", "Erase diversion"),
+("playAllDiversions()", "Stop diverting and play all diversions in order"),
+("replayAllDiversions()", "Stop diverting and replay all diversions"),
+("purgeAllDiversions()", "Stop diverting and purge all diversions"),
+("getFilter()", "Get current filter"),
+("resetFilter()", "Reset filter; no filtering"),
+("nullFilter()", "Install null filter"),
+("setFilter(shortcut)", "Install new filter or filter chain"),
+("attachFilter(shortcut)", "Attach single filter to end of current chain"),
+("areHooksEnabled()", "Return whether or not hooks are enabled"),
+("enableHooks()", "Enable hooks (default)"),
+("disableHooks()", "Disable hook invocation"),
+("getHooks()", "Get all the hooks"),
+("clearHooks()", "Clear all hooks"),
+("addHook(hook, [i])", "Register the hook (optionally insert)"),
+("removeHook(hook)", "Remove an already-registered hook from name"),
+("invokeHook(name_, ...)", "Manually invoke hook"),
+("getCallback()", "Get interpreter callback"),
+("registerCallback(callback)", "Register callback with interpreter"),
+("deregisterCallback()", "Deregister callback from interpreter"),
+("invokeCallback(contents)", "Invoke the callback directly"),
+("Interpreter", "The interpreter class"),
+]
+
+ENVIRONMENT_INFO = [
+(OPTIONS_ENV, "Specified options will be included"),
+(PREFIX_ENV, "Specify the default prefix: -p <value>"),
+(PSEUDO_ENV, "Specify name of pseudomodule: -m <value>"),
+(FLATTEN_ENV, "Flatten empy pseudomodule if defined: -f"),
+(RAW_ENV, "Show raw errors if defined: -r"),
+(INTERACTIVE_ENV, "Enter interactive mode if defined: -i"),
+(BUFFERED_ENV, "Fully buffered output if defined: -b"),
+(NO_OVERRIDE_ENV, "Do not override sys.stdout if defined: -n"),
+(UNICODE_ENV, "Enable Unicode subsystem: -n"),
+(INPUT_ENCODING_ENV, "Unicode input encoding"),
+(OUTPUT_ENCODING_ENV, "Unicode output encoding"),
+(INPUT_ERRORS_ENV, "Unicode input error handler"),
+(OUTPUT_ERRORS_ENV, "Unicode output error handler"),
+]
+
+class Error(Exception):
+ """The base class for all EmPy errors."""
+ pass
+
+EmpyError = EmPyError = Error # DEPRECATED
+
+class DiversionError(Error):
+ """An error related to diversions."""
+ pass
+
+class FilterError(Error):
+ """An error related to filters."""
+ pass
+
+class StackUnderflowError(Error):
+ """A stack underflow."""
+ pass
+
+class SubsystemError(Error):
+ """An error associated with the Unicode subsystem."""
+ pass
+
+class FlowError(Error):
+ """An exception related to control flow."""
+ pass
+
+class ContinueFlow(FlowError):
+ """A continue control flow."""
+ pass
+
+class BreakFlow(FlowError):
+ """A break control flow."""
+ pass
+
+class ParseError(Error):
+ """A parse error occurred."""
+ pass
+
+class TransientParseError(ParseError):
+ """A parse error occurred which may be resolved by feeding more data.
+ Such an error reaching the toplevel is an unexpected EOF error."""
+ pass
+
+
+class MetaError(Exception):
+
+ """A wrapper around a real Python exception for including a copy of
+ the context."""
+
+ def __init__(self, contexts, exc):
+ Exception.__init__(self, exc)
+ self.contexts = contexts
+ self.exc = exc
+
+ def __str__(self):
+ backtrace = map(lambda x: str(x), self.contexts)
+ return "%s: %s (%s)" % (self.exc.__class__, self.exc, \
+ (string.join(backtrace, ', ')))
+
+
+class Subsystem:
+
+ """The subsystem class defers file creation so that it can create
+ Unicode-wrapped files if desired (and possible)."""
+
+ def __init__(self):
+ self.useUnicode = False
+ self.inputEncoding = None
+ self.outputEncoding = None
+ self.errors = None
+
+ def initialize(self, inputEncoding=None, outputEncoding=None, \
+ inputErrors=None, outputErrors=None):
+ self.useUnicode = True
+ try:
+ unicode
+ import codecs
+ except (NameError, ImportError):
+ raise SubsystemError, "Unicode subsystem unavailable"
+ defaultEncoding = sys.getdefaultencoding()
+ if inputEncoding is None:
+ inputEncoding = defaultEncoding
+ self.inputEncoding = inputEncoding
+ if outputEncoding is None:
+ outputEncoding = defaultEncoding
+ self.outputEncoding = outputEncoding
+ if inputErrors is None:
+ inputErrors = DEFAULT_ERRORS
+ self.inputErrors = inputErrors
+ if outputErrors is None:
+ outputErrors = DEFAULT_ERRORS
+ self.outputErrors = outputErrors
+
+ def assertUnicode(self):
+ if not self.useUnicode:
+ raise SubsystemError, "Unicode subsystem unavailable"
+
+ def open(self, name, mode=None):
+ if self.useUnicode:
+ return self.unicodeOpen(name, mode)
+ else:
+ return self.defaultOpen(name, mode)
+
+ def defaultOpen(self, name, mode=None):
+ if mode is None:
+ mode = 'r'
+ return open(name, mode)
+
+ def unicodeOpen(self, name, mode=None):
+ import codecs
+ if mode is None:
+ mode = 'rb'
+ if mode.find('w') >= 0 or mode.find('a') >= 0:
+ encoding = self.outputEncoding
+ errors = self.outputErrors
+ else:
+ encoding = self.inputEncoding
+ errors = self.inputErrors
+ return codecs.open(name, mode, encoding, errors)
+
+theSubsystem = Subsystem()
+
+
+class Stack:
+
+ """A simple stack that behaves as a sequence (with 0 being the top
+ of the stack, not the bottom)."""
+
+ def __init__(self, seq=None):
+ if seq is None:
+ seq = []
+ self.data = seq
+
+ def top(self):
+ """Access the top element on the stack."""
+ try:
+ return self.data[-1]
+ except IndexError:
+ raise StackUnderflowError, "stack is empty for top"
+
+ def pop(self):
+ """Pop the top element off the stack and return it."""
+ try:
+ return self.data.pop()
+ except IndexError:
+ raise StackUnderflowError, "stack is empty for pop"
+
+ def push(self, object):
+ """Push an element onto the top of the stack."""
+ self.data.append(object)
+
+ def filter(self, function):
+ """Filter the elements of the stack through the function."""
+ self.data = filter(function, self.data)
+
+ def purge(self):
+ """Purge the stack."""
+ self.data = []
+
+ def clone(self):
+ """Create a duplicate of this stack."""
+ return self.__class__(self.data[:])
+
+ def __nonzero__(self): return len(self.data) != 0
+ def __len__(self): return len(self.data)
+ def __getitem__(self, index): return self.data[-(index + 1)]
+
+ def __repr__(self):
+ return '<%s instance at 0x%x [%s]>' % \
+ (self.__class__, id(self), \
+ string.join(map(repr, self.data), ', '))
+
+
+class AbstractFile:
+
+ """An abstracted file that, when buffered, will totally buffer the
+ file, including even the file open."""
+
+ def __init__(self, filename, mode='w', buffered=False):
+ # The calls below might throw, so start off by marking this
+ # file as "done." This way destruction of a not-completely-
+ # initialized AbstractFile will generate no further errors.
+ self.done = True
+ self.filename = filename
+ self.mode = mode
+ self.buffered = buffered
+ if buffered:
+ self.bufferFile = StringIO.StringIO()
+ else:
+ self.bufferFile = theSubsystem.open(filename, mode)
+ # Okay, we got this far, so the AbstractFile is initialized.
+ # Flag it as "not done."
+ self.done = False
+
+ def __del__(self):
+ self.close()
+
+ def write(self, data):
+ self.bufferFile.write(data)
+
+ def writelines(self, data):
+ self.bufferFile.writelines(data)
+
+ def flush(self):
+ self.bufferFile.flush()
+
+ def close(self):
+ if not self.done:
+ self.commit()
+ self.done = True
+
+ def commit(self):
+ if self.buffered:
+ file = theSubsystem.open(self.filename, self.mode)
+ file.write(self.bufferFile.getvalue())
+ file.close()
+ else:
+ self.bufferFile.close()
+
+ def abort(self):
+ if self.buffered:
+ self.bufferFile = None
+ else:
+ self.bufferFile.close()
+ self.bufferFile = None
+ self.done = True
+
+
+class Diversion:
+
+ """The representation of an active diversion. Diversions act as
+ (writable) file objects, and then can be recalled either as pure
+ strings or (readable) file objects."""
+
+ def __init__(self):
+ self.file = StringIO.StringIO()
+
+ # These methods define the writable file-like interface for the
+ # diversion.
+
+ def write(self, data):
+ self.file.write(data)
+
+ def writelines(self, lines):
+ for line in lines:
+ self.write(line)
+
+ def flush(self):
+ self.file.flush()
+
+ def close(self):
+ self.file.close()
+
+ # These methods are specific to diversions.
+
+ def asString(self):
+ """Return the diversion as a string."""
+ return self.file.getvalue()
+
+ def asFile(self):
+ """Return the diversion as a file."""
+ return StringIO.StringIO(self.file.getvalue())
+
+
+class Stream:
+
+ """A wrapper around an (output) file object which supports
+ diversions and filtering."""
+
+ def __init__(self, file):
+ self.file = file
+ self.currentDiversion = None
+ self.diversions = {}
+ self.filter = file
+ self.done = False
+
+ def write(self, data):
+ if self.currentDiversion is None:
+ self.filter.write(data)
+ else:
+ self.diversions[self.currentDiversion].write(data)
+
+ def writelines(self, lines):
+ for line in lines:
+ self.write(line)
+
+ def flush(self):
+ self.filter.flush()
+
+ def close(self):
+ if not self.done:
+ self.undivertAll(True)
+ self.filter.close()
+ self.done = True
+
+ def shortcut(self, shortcut):
+ """Take a filter shortcut and translate it into a filter, returning
+ it. Sequences don't count here; these should be detected
+ independently."""
+ if shortcut == 0:
+ return NullFilter()
+ elif type(shortcut) is types.FunctionType or \
+ type(shortcut) is types.BuiltinFunctionType or \
+ type(shortcut) is types.BuiltinMethodType or \
+ type(shortcut) is types.LambdaType:
+ return FunctionFilter(shortcut)
+ elif type(shortcut) is types.StringType:
+ return StringFilter(filter)
+ elif type(shortcut) is types.DictType:
+ raise NotImplementedError, "mapping filters not yet supported"
+ else:
+ # Presume it's a plain old filter.
+ return shortcut
+
+ def last(self):
+ """Find the last filter in the current filter chain, or None if
+ there are no filters installed."""
+ if self.filter is None:
+ return None
+ thisFilter, lastFilter = self.filter, None
+ while thisFilter is not None and thisFilter is not self.file:
+ lastFilter = thisFilter
+ thisFilter = thisFilter.next()
+ return lastFilter
+
+ def install(self, shortcut=None):
+ """Install a new filter; None means no filter. Handle all the
+ special shortcuts for filters here."""
+ # Before starting, execute a flush.
+ self.filter.flush()
+ if shortcut is None or shortcut == [] or shortcut == ():
+ # Shortcuts for "no filter."
+ self.filter = self.file
+ else:
+ if type(shortcut) in (types.ListType, types.TupleType):
+ shortcuts = list(shortcut)
+ else:
+ shortcuts = [shortcut]
+ # Run through the shortcut filter names, replacing them with
+ # full-fledged instances of Filter.
+ filters = []
+ for shortcut in shortcuts:
+ filters.append(self.shortcut(shortcut))
+ if len(filters) > 1:
+ # If there's more than one filter provided, chain them
+ # together.
+ lastFilter = None
+ for filter in filters:
+ if lastFilter is not None:
+ lastFilter.attach(filter)
+ lastFilter = filter
+ lastFilter.attach(self.file)
+ self.filter = filters[0]
+ else:
+ # If there's only one filter, assume that it's alone or it's
+ # part of a chain that has already been manually chained;
+ # just find the end.
+ filter = filters[0]
+ lastFilter = filter.last()
+ lastFilter.attach(self.file)
+ self.filter = filter
+
+ def attach(self, shortcut):
+ """Attached a solitary filter (no sequences allowed here) at the
+ end of the current filter chain."""
+ lastFilter = self.last()
+ if lastFilter is None:
+ # Just install it from scratch if there is no active filter.
+ self.install(shortcut)
+ else:
+ # Attach the last filter to this one, and this one to the file.
+ filter = self.shortcut(shortcut)
+ lastFilter.attach(filter)
+ filter.attach(self.file)
+
+ def revert(self):
+ """Reset any current diversions."""
+ self.currentDiversion = None
+
+ def create(self, name):
+ """Create a diversion if one does not already exist, but do not
+ divert to it yet."""
+ if name is None:
+ raise DiversionError, "diversion name must be non-None"
+ if not self.diversions.has_key(name):
+ self.diversions[name] = Diversion()
+
+ def retrieve(self, name):
+ """Retrieve the given diversion."""
+ if name is None:
+ raise DiversionError, "diversion name must be non-None"
+ if self.diversions.has_key(name):
+ return self.diversions[name]
+ else:
+ raise DiversionError, "nonexistent diversion: %s" % name
+
+ def divert(self, name):
+ """Start diverting."""
+ if name is None:
+ raise DiversionError, "diversion name must be non-None"
+ self.create(name)
+ self.currentDiversion = name
+
+ def undivert(self, name, purgeAfterwards=False):
+ """Undivert a particular diversion."""
+ if name is None:
+ raise DiversionError, "diversion name must be non-None"
+ if self.diversions.has_key(name):
+ diversion = self.diversions[name]
+ self.filter.write(diversion.asString())
+ if purgeAfterwards:
+ self.purge(name)
+ else:
+ raise DiversionError, "nonexistent diversion: %s" % name
+
+ def purge(self, name):
+ """Purge the specified diversion."""
+ if name is None:
+ raise DiversionError, "diversion name must be non-None"
+ if self.diversions.has_key(name):
+ del self.diversions[name]
+ if self.currentDiversion == name:
+ self.currentDiversion = None
+
+ def undivertAll(self, purgeAfterwards=True):
+ """Undivert all pending diversions."""
+ if self.diversions:
+ self.revert() # revert before undiverting!
+ names = self.diversions.keys()
+ names.sort()
+ for name in names:
+ self.undivert(name)
+ if purgeAfterwards:
+ self.purge(name)
+
+ def purgeAll(self):
+ """Eliminate all existing diversions."""
+ if self.diversions:
+ self.diversions = {}
+ self.currentDiversion = None
+
+
+class NullFile:
+
+ """A simple class that supports all the file-like object methods
+ but simply does nothing at all."""
+
+ def __init__(self): pass
+ def write(self, data): pass
+ def writelines(self, lines): pass
+ def flush(self): pass
+ def close(self): pass
+
+
+class UncloseableFile:
+
+ """A simple class which wraps around a delegate file-like object
+ and lets everything through except close calls."""
+
+ def __init__(self, delegate):
+ self.delegate = delegate
+
+ def write(self, data):
+ self.delegate.write(data)
+
+ def writelines(self, lines):
+ self.delegate.writelines(data)
+
+ def flush(self):
+ self.delegate.flush()
+
+ def close(self):
+ """Eat this one."""
+ pass
+
+
+class ProxyFile:
+
+ """The proxy file object that is intended to take the place of
+ sys.stdout. The proxy can manage a stack of file objects it is
+ writing to, and an underlying raw file object."""
+
+ def __init__(self, bottom):
+ self.stack = Stack()
+ self.bottom = bottom
+
+ def current(self):
+ """Get the current stream to write to."""
+ if self.stack:
+ return self.stack[-1][1]
+ else:
+ return self.bottom
+
+ def push(self, interpreter):
+ self.stack.push((interpreter, interpreter.stream()))
+
+ def pop(self, interpreter):
+ result = self.stack.pop()
+ assert interpreter is result[0]
+
+ def clear(self, interpreter):
+ self.stack.filter(lambda x, i=interpreter: x[0] is not i)
+
+ def write(self, data):
+ self.current().write(data)
+
+ def writelines(self, lines):
+ self.current().writelines(lines)
+
+ def flush(self):
+ self.current().flush()
+
+ def close(self):
+ """Close the current file. If the current file is the bottom, then
+ close it and dispose of it."""
+ current = self.current()
+ if current is self.bottom:
+ self.bottom = None
+ current.close()
+
+ def _testProxy(self): pass
+
+
+class Filter:
+
+ """An abstract filter."""
+
+ def __init__(self):
+ if self.__class__ is Filter:
+ raise NotImplementedError
+ self.sink = None
+
+ def next(self):
+ """Return the next filter/file-like object in the sequence, or None."""
+ return self.sink
+
+ def write(self, data):
+ """The standard write method; this must be overridden in subclasses."""
+ raise NotImplementedError
+
+ def writelines(self, lines):
+ """Standard writelines wrapper."""
+ for line in lines:
+ self.write(line)
+
+ def _flush(self):
+ """The _flush method should always flush the sink and should not
+ be overridden."""
+ self.sink.flush()
+
+ def flush(self):
+ """The flush method can be overridden."""
+ self._flush()
+
+ def close(self):
+ """Close the filter. Do an explicit flush first, then close the
+ sink."""
+ self.flush()
+ self.sink.close()
+
+ def attach(self, filter):
+ """Attach a filter to this one."""
+ if self.sink is not None:
+ # If it's already attached, detach it first.
+ self.detach()
+ self.sink = filter
+
+ def detach(self):
+ """Detach a filter from its sink."""
+ self.flush()
+ self._flush() # do a guaranteed flush to just to be safe
+ self.sink = None
+
+ def last(self):
+ """Find the last filter in this chain."""
+ this, last = self, self
+ while this is not None:
+ last = this
+ this = this.next()
+ return last
+
+class NullFilter(Filter):
+
+ """A filter that never sends any output to its sink."""
+
+ def write(self, data): pass
+
+class FunctionFilter(Filter):
+
+ """A filter that works simply by pumping its input through a
+ function which maps strings into strings."""
+
+ def __init__(self, function):
+ Filter.__init__(self)
+ self.function = function
+
+ def write(self, data):
+ self.sink.write(self.function(data))
+
+class StringFilter(Filter):
+
+ """A filter that takes a translation string (256 characters) and
+ filters any incoming data through it."""
+
+ def __init__(self, table):
+ if not (type(table) == types.StringType and len(table) == 256):
+ raise FilterError, "table must be 256-character string"
+ Filter.__init__(self)
+ self.table = table
+
+ def write(self, data):
+ self.sink.write(string.translate(data, self.table))
+
+class BufferedFilter(Filter):
+
+ """A buffered filter is one that doesn't modify the source data
+ sent to the sink, but instead holds it for a time. The standard
+ variety only sends the data along when it receives a flush
+ command."""
+
+ def __init__(self):
+ Filter.__init__(self)
+ self.buffer = ''
+
+ def write(self, data):
+ self.buffer = self.buffer + data
+
+ def flush(self):
+ if self.buffer:
+ self.sink.write(self.buffer)
+ self._flush()
+
+class SizeBufferedFilter(BufferedFilter):
+
+ """A size-buffered filter only in fixed size chunks (excepting the
+ final chunk)."""
+
+ def __init__(self, bufferSize):
+ BufferedFilter.__init__(self)
+ self.bufferSize = bufferSize
+
+ def write(self, data):
+ BufferedFilter.write(self, data)
+ while len(self.buffer) > self.bufferSize:
+ chunk, self.buffer = \
+ self.buffer[:self.bufferSize], self.buffer[self.bufferSize:]
+ self.sink.write(chunk)
+
+class LineBufferedFilter(BufferedFilter):
+
+ """A line-buffered filter only lets data through when it sees
+ whole lines."""
+
+ def __init__(self):
+ BufferedFilter.__init__(self)
+
+ def write(self, data):
+ BufferedFilter.write(self, data)
+ chunks = string.split(self.buffer, '\n')
+ for chunk in chunks[:-1]:
+ self.sink.write(chunk + '\n')
+ self.buffer = chunks[-1]
+
+class MaximallyBufferedFilter(BufferedFilter):
+
+ """A maximally-buffered filter only lets its data through on the final
+ close. It ignores flushes."""
+
+ def __init__(self):
+ BufferedFilter.__init__(self)
+
+ def flush(self): pass
+
+ def close(self):
+ if self.buffer:
+ BufferedFilter.flush(self)
+ self.sink.close()
+
+
+class Context:
+
+ """An interpreter context, which encapsulates a name, an input
+ file object, and a parser object."""
+
+ DEFAULT_UNIT = 'lines'
+
+ def __init__(self, name, line=0, units=DEFAULT_UNIT):
+ self.name = name
+ self.line = line
+ self.units = units
+ self.pause = False
+
+ def bump(self, quantity=1):
+ if self.pause:
+ self.pause = False
+ else:
+ self.line = self.line + quantity
+
+ def identify(self):
+ return self.name, self.line
+
+ def __str__(self):
+ if self.units == self.DEFAULT_UNIT:
+ return "%s:%s" % (self.name, self.line)
+ else:
+ return "%s:%s[%s]" % (self.name, self.line, self.units)
+
+
+class Hook:
+
+ """The base class for implementing hooks."""
+
+ def __init__(self):
+ self.interpreter = None
+
+ def register(self, interpreter):
+ self.interpreter = interpreter
+
+ def deregister(self, interpreter):
+ if interpreter is not self.interpreter:
+ raise Error, "hook not associated with this interpreter"
+ self.interpreter = None
+
+ def push(self):
+ self.interpreter.push()
+
+ def pop(self):
+ self.interpreter.pop()
+
+ def null(self): pass
+
+ def atStartup(self): pass
+ def atReady(self): pass
+ def atFinalize(self): pass
+ def atShutdown(self): pass
+ def atParse(self, scanner, locals): pass
+ def atToken(self, token): pass
+ def atHandle(self, meta): pass
+ def atInteract(self): pass
+
+ def beforeInclude(self, name, file, locals): pass
+ def afterInclude(self): pass
+
+ def beforeExpand(self, string, locals): pass
+ def afterExpand(self, result): pass
+
+ def beforeFile(self, name, file, locals): pass
+ def afterFile(self): pass
+
+ def beforeBinary(self, name, file, chunkSize, locals): pass
+ def afterBinary(self): pass
+
+ def beforeString(self, name, string, locals): pass
+ def afterString(self): pass
+
+ def beforeQuote(self, string): pass
+ def afterQuote(self, result): pass
+
+ def beforeEscape(self, string, more): pass
+ def afterEscape(self, result): pass
+
+ def beforeControl(self, type, rest, locals): pass
+ def afterControl(self): pass
+
+ def beforeSignificate(self, key, value, locals): pass
+ def afterSignificate(self): pass
+
+ def beforeAtomic(self, name, value, locals): pass
+ def afterAtomic(self): pass
+
+ def beforeMulti(self, name, values, locals): pass
+ def afterMulti(self): pass
+
+ def beforeImport(self, name, locals): pass
+ def afterImport(self): pass
+
+ def beforeClause(self, catch, locals): pass
+ def afterClause(self, exception, variable): pass
+
+ def beforeSerialize(self, expression, locals): pass
+ def afterSerialize(self): pass
+
+ def beforeDefined(self, name, locals): pass
+ def afterDefined(self, result): pass
+
+ def beforeLiteral(self, text): pass
+ def afterLiteral(self): pass
+
+ def beforeEvaluate(self, expression, locals): pass
+ def afterEvaluate(self, result): pass
+
+ def beforeExecute(self, statements, locals): pass
+ def afterExecute(self): pass
+
+ def beforeSingle(self, source, locals): pass
+ def afterSingle(self): pass
+
+class VerboseHook(Hook):
+
+ """A verbose hook that reports all information received by the
+ hook interface. This class dynamically scans the Hook base class
+ to ensure that all hook methods are properly represented."""
+
+ EXEMPT_ATTRIBUTES = ['register', 'deregister', 'push', 'pop']
+
+ def __init__(self, output=sys.stderr):
+ Hook.__init__(self)
+ self.output = output
+ self.indent = 0
+
+ class FakeMethod:
+ """This is a proxy method-like object."""
+ def __init__(self, hook, name):
+ self.hook = hook
+ self.name = name
+
+ def __call__(self, **keywords):
+ self.hook.output.write("%s%s: %s\n" % \
+ (' ' * self.hook.indent, \
+ self.name, repr(keywords)))
+
+ for attribute in dir(Hook):
+ if attribute[:1] != '_' and \
+ attribute not in self.EXEMPT_ATTRIBUTES:
+ self.__dict__[attribute] = FakeMethod(self, attribute)
+
+
+class Token:
+
+ """An element of expansion."""
+
+ def run(self, interpreter, locals):
+ raise NotImplementedError
+
+ def string(self):
+ raise NotImplementedError
+
+ def __str__(self): return self.string()
+
+class NullToken(Token):
+ """A chunk of data not containing markups."""
+ def __init__(self, data):
+ self.data = data
+
+ def run(self, interpreter, locals):
+ interpreter.write(self.data)
+
+ def string(self):
+ return self.data
+
+class ExpansionToken(Token):
+ """A token that involves an expansion."""
+ def __init__(self, prefix, first):
+ self.prefix = prefix
+ self.first = first
+
+ def scan(self, scanner):
+ pass
+
+ def run(self, interpreter, locals):
+ pass
+
+class WhitespaceToken(ExpansionToken):
+ """A whitespace markup."""
+ def string(self):
+ return '%s%s' % (self.prefix, self.first)
+
+class LiteralToken(ExpansionToken):
+ """A literal markup."""
+ def run(self, interpreter, locals):
+ interpreter.write(self.first)
+
+ def string(self):
+ return '%s%s' % (self.prefix, self.first)
+
+class PrefixToken(ExpansionToken):
+ """A prefix markup."""
+ def run(self, interpreter, locals):
+ interpreter.write(interpreter.prefix)
+
+ def string(self):
+ return self.prefix * 2
+
+class CommentToken(ExpansionToken):
+ """A comment markup."""
+ def scan(self, scanner):
+ loc = scanner.find('\n')
+ if loc >= 0:
+ self.comment = scanner.chop(loc, 1)
+ else:
+ raise TransientParseError, "comment expects newline"
+
+ def string(self):
+ return '%s#%s\n' % (self.prefix, self.comment)
+
+class ContextNameToken(ExpansionToken):
+ """A context name change markup."""
+ def scan(self, scanner):
+ loc = scanner.find('\n')
+ if loc >= 0:
+ self.name = string.strip(scanner.chop(loc, 1))
+ else:
+ raise TransientParseError, "context name expects newline"
+
+ def run(self, interpreter, locals):
+ context = interpreter.context()
+ context.name = self.name
+
+class ContextLineToken(ExpansionToken):
+ """A context line change markup."""
+ def scan(self, scanner):
+ loc = scanner.find('\n')
+ if loc >= 0:
+ try:
+ self.line = int(scanner.chop(loc, 1))
+ except ValueError:
+ raise ParseError, "context line requires integer"
+ else:
+ raise TransientParseError, "context line expects newline"
+
+ def run(self, interpreter, locals):
+ context = interpreter.context()
+ context.line = self.line
+ context.pause = True
+
+class EscapeToken(ExpansionToken):
+ """An escape markup."""
+ def scan(self, scanner):
+ try:
+ code = scanner.chop(1)
+ result = None
+ if code in '()[]{}\'\"\\': # literals
+ result = code
+ elif code == '0': # NUL
+ result = '\x00'
+ elif code == 'a': # BEL
+ result = '\x07'
+ elif code == 'b': # BS
+ result = '\x08'
+ elif code == 'd': # decimal code
+ decimalCode = scanner.chop(3)
+ result = chr(string.atoi(decimalCode, 10))
+ elif code == 'e': # ESC
+ result = '\x1b'
+ elif code == 'f': # FF
+ result = '\x0c'
+ elif code == 'h': # DEL
+ result = '\x7f'
+ elif code == 'n': # LF (newline)
+ result = '\x0a'
+ elif code == 'N': # Unicode character name
+ theSubsystem.assertUnicode()
+ import unicodedata
+ if scanner.chop(1) != '{':
+ raise ParseError, r"Unicode name escape should be \N{...}"
+ i = scanner.find('}')
+ name = scanner.chop(i, 1)
+ try:
+ result = unicodedata.lookup(name)
+ except KeyError:
+ raise SubsystemError, \
+ "unknown Unicode character name: %s" % name
+ elif code == 'o': # octal code
+ octalCode = scanner.chop(3)
+ result = chr(string.atoi(octalCode, 8))
+ elif code == 'q': # quaternary code
+ quaternaryCode = scanner.chop(4)
+ result = chr(string.atoi(quaternaryCode, 4))
+ elif code == 'r': # CR
+ result = '\x0d'
+ elif code in 's ': # SP
+ result = ' '
+ elif code == 't': # HT
+ result = '\x09'
+ elif code in 'u': # Unicode 16-bit hex literal
+ theSubsystem.assertUnicode()
+ hexCode = scanner.chop(4)
+ result = unichr(string.atoi(hexCode, 16))
+ elif code in 'U': # Unicode 32-bit hex literal
+ theSubsystem.assertUnicode()
+ hexCode = scanner.chop(8)
+ result = unichr(string.atoi(hexCode, 16))
+ elif code == 'v': # VT
+ result = '\x0b'
+ elif code == 'x': # hexadecimal code
+ hexCode = scanner.chop(2)
+ result = chr(string.atoi(hexCode, 16))
+ elif code == 'z': # EOT
+ result = '\x04'
+ elif code == '^': # control character
+ controlCode = string.upper(scanner.chop(1))
+ if controlCode >= '@' and controlCode <= '`':
+ result = chr(ord(controlCode) - ord('@'))
+ elif controlCode == '?':
+ result = '\x7f'
+ else:
+ raise ParseError, "invalid escape control code"
+ else:
+ raise ParseError, "unrecognized escape code"
+ assert result is not None
+ self.code = result
+ except ValueError:
+ raise ParseError, "invalid numeric escape code"
+
+ def run(self, interpreter, locals):
+ interpreter.write(self.code)
+
+ def string(self):
+ return '%s\\x%02x' % (self.prefix, ord(self.code))
+
+class SignificatorToken(ExpansionToken):
+ """A significator markup."""
+ def scan(self, scanner):
+ loc = scanner.find('\n')
+ if loc >= 0:
+ line = scanner.chop(loc, 1)
+ if not line:
+ raise ParseError, "significator must have nonblank key"
+ if line[0] in ' \t\v\n':
+ raise ParseError, "no whitespace between % and key"
+ # Work around a subtle CPython-Jython difference by stripping
+ # the string before splitting it: 'a '.split(None, 1) has two
+ # elements in Jython 2.1).
+ fields = string.split(string.strip(line), None, 1)
+ if len(fields) == 2 and fields[1] == '':
+ fields.pop()
+ self.key = fields[0]
+ if len(fields) < 2:
+ fields.append(None)
+ self.key, self.valueCode = fields
+ else:
+ raise TransientParseError, "significator expects newline"
+
+ def run(self, interpreter, locals):
+ value = self.valueCode
+ if value is not None:
+ value = interpreter.evaluate(string.strip(value), locals)
+ interpreter.significate(self.key, value)
+
+ def string(self):
+ if self.valueCode is None:
+ return '%s%%%s\n' % (self.prefix, self.key)
+ else:
+ return '%s%%%s %s\n' % (self.prefix, self.key, self.valueCode)
+
+class ExpressionToken(ExpansionToken):
+ """An expression markup."""
+ def scan(self, scanner):
+ z = scanner.complex('(', ')', 0)
+ try:
+ q = scanner.next('$', 0, z, True)
+ except ParseError:
+ q = z
+ try:
+ i = scanner.next('?', 0, q, True)
+ try:
+ j = scanner.next('!', i, q, True)
+ except ParseError:
+ try:
+ j = scanner.next(':', i, q, True) # DEPRECATED
+ except ParseError:
+ j = q
+ except ParseError:
+ i = j = q
+ code = scanner.chop(z, 1)
+ self.testCode = code[:i]
+ self.thenCode = code[i + 1:j]
+ self.elseCode = code[j + 1:q]
+ self.exceptCode = code[q + 1:z]
+
+ def run(self, interpreter, locals):
+ try:
+ result = interpreter.evaluate(self.testCode, locals)
+ if self.thenCode:
+ if result:
+ result = interpreter.evaluate(self.thenCode, locals)
+ else:
+ if self.elseCode:
+ result = interpreter.evaluate(self.elseCode, locals)
+ else:
+ result = None
+ except SyntaxError:
+ # Don't catch syntax errors; let them through.
+ raise
+ except:
+ if self.exceptCode:
+ result = interpreter.evaluate(self.exceptCode, locals)
+ else:
+ raise
+ if result is not None:
+ interpreter.write(str(result))
+
+ def string(self):
+ result = self.testCode
+ if self.thenCode:
+ result = result + '?' + self.thenCode
+ if self.elseCode:
+ result = result + '!' + self.elseCode
+ if self.exceptCode:
+ result = result + '$' + self.exceptCode
+ return '%s(%s)' % (self.prefix, result)
+
+class StringLiteralToken(ExpansionToken):
+ """A string token markup."""
+ def scan(self, scanner):
+ scanner.retreat()
+ assert scanner[0] == self.first
+ i = scanner.quote()
+ self.literal = scanner.chop(i)
+
+ def run(self, interpreter, locals):
+ interpreter.literal(self.literal)
+
+ def string(self):
+ return '%s%s' % (self.prefix, self.literal)
+
+class SimpleExpressionToken(ExpansionToken):
+ """A simple expression markup."""
+ def scan(self, scanner):
+ i = scanner.simple()
+ self.code = self.first + scanner.chop(i)
+
+ def run(self, interpreter, locals):
+ interpreter.serialize(self.code, locals)
+
+ def string(self):
+ return '%s%s' % (self.prefix, self.code)
+
+class ReprToken(ExpansionToken):
+ """A repr markup."""
+ def scan(self, scanner):
+ i = scanner.next('`', 0)
+ self.code = scanner.chop(i, 1)
+
+ def run(self, interpreter, locals):
+ interpreter.write(repr(interpreter.evaluate(self.code, locals)))
+
+ def string(self):
+ return '%s`%s`' % (self.prefix, self.code)
+
+class InPlaceToken(ExpansionToken):
+ """An in-place markup."""
+ def scan(self, scanner):
+ i = scanner.next(':', 0)
+ j = scanner.next(':', i + 1)
+ self.code = scanner.chop(i, j - i + 1)
+
+ def run(self, interpreter, locals):
+ interpreter.write("%s:%s:" % (interpreter.prefix, self.code))
+ try:
+ interpreter.serialize(self.code, locals)
+ finally:
+ interpreter.write(":")
+
+ def string(self):
+ return '%s:%s::' % (self.prefix, self.code)
+
+class StatementToken(ExpansionToken):
+ """A statement markup."""
+ def scan(self, scanner):
+ i = scanner.complex('{', '}', 0)
+ self.code = scanner.chop(i, 1)
+
+ def run(self, interpreter, locals):
+ interpreter.execute(self.code, locals)
+
+ def string(self):
+ return '%s{%s}' % (self.prefix, self.code)
+
+class CustomToken(ExpansionToken):
+ """A custom markup."""
+ def scan(self, scanner):
+ i = scanner.complex('<', '>', 0)
+ self.contents = scanner.chop(i, 1)
+
+ def run(self, interpreter, locals):
+ interpreter.invokeCallback(self.contents)
+
+ def string(self):
+ return '%s<%s>' % (self.prefix, self.contents)
+
+class ControlToken(ExpansionToken):
+
+ """A control token."""
+
+ PRIMARY_TYPES = ['if', 'for', 'while', 'try', 'def']
+ SECONDARY_TYPES = ['elif', 'else', 'except', 'finally']
+ TERTIARY_TYPES = ['continue', 'break']
+ GREEDY_TYPES = ['if', 'elif', 'for', 'while', 'def', 'end']
+ END_TYPES = ['end']
+
+ IN_RE = re.compile(r"\bin\b")
+
+ def scan(self, scanner):
+ scanner.acquire()
+ i = scanner.complex('[', ']', 0)
+ self.contents = scanner.chop(i, 1)
+ fields = string.split(string.strip(self.contents), ' ', 1)
+ if len(fields) > 1:
+ self.type, self.rest = fields
+ else:
+ self.type = fields[0]
+ self.rest = None
+ self.subtokens = []
+ if self.type in self.GREEDY_TYPES and self.rest is None:
+ raise ParseError, "control '%s' needs arguments" % self.type
+ if self.type in self.PRIMARY_TYPES:
+ self.subscan(scanner, self.type)
+ self.kind = 'primary'
+ elif self.type in self.SECONDARY_TYPES:
+ self.kind = 'secondary'
+ elif self.type in self.TERTIARY_TYPES:
+ self.kind = 'tertiary'
+ elif self.type in self.END_TYPES:
+ self.kind = 'end'
+ else:
+ raise ParseError, "unknown control markup: '%s'" % self.type
+ scanner.release()
+
+ def subscan(self, scanner, primary):
+ """Do a subscan for contained tokens."""
+ while True:
+ token = scanner.one()
+ if token is None:
+ raise TransientParseError, \
+ "control '%s' needs more tokens" % primary
+ if isinstance(token, ControlToken) and \
+ token.type in self.END_TYPES:
+ if token.rest != primary:
+ raise ParseError, \
+ "control must end with 'end %s'" % primary
+ break
+ self.subtokens.append(token)
+
+ def build(self, allowed=None):
+ """Process the list of subtokens and divide it into a list of
+ 2-tuples, consisting of the dividing tokens and the list of
+ subtokens that follow them. If allowed is specified, it will
+ represent the list of the only secondary markup types which
+ are allowed."""
+ if allowed is None:
+ allowed = SECONDARY_TYPES
+ result = []
+ latest = []
+ result.append((self, latest))
+ for subtoken in self.subtokens:
+ if isinstance(subtoken, ControlToken) and \
+ subtoken.kind == 'secondary':
+ if subtoken.type not in allowed:
+ raise ParseError, \
+ "control unexpected secondary: '%s'" % subtoken.type
+ latest = []
+ result.append((subtoken, latest))
+ else:
+ latest.append(subtoken)
+ return result
+
+ def run(self, interpreter, locals):
+ interpreter.invoke('beforeControl', type=self.type, rest=self.rest, \
+ locals=locals)
+ if self.type == 'if':
+ info = self.build(['elif', 'else'])
+ elseTokens = None
+ if info[-1][0].type == 'else':
+ elseTokens = info.pop()[1]
+ for secondary, subtokens in info:
+ if secondary.type not in ('if', 'elif'):
+ raise ParseError, \
+ "control 'if' unexpected secondary: '%s'" % secondary.type
+ if interpreter.evaluate(secondary.rest, locals):
+ self.subrun(subtokens, interpreter, locals)
+ break
+ else:
+ if elseTokens:
+ self.subrun(elseTokens, interpreter, locals)
+ elif self.type == 'for':
+ sides = self.IN_RE.split(self.rest, 1)
+ if len(sides) != 2:
+ raise ParseError, "control expected 'for x in seq'"
+ iterator, sequenceCode = sides
+ info = self.build(['else'])
+ elseTokens = None
+ if info[-1][0].type == 'else':
+ elseTokens = info.pop()[1]
+ if len(info) != 1:
+ raise ParseError, "control 'for' expects at most one 'else'"
+ sequence = interpreter.evaluate(sequenceCode, locals)
+ for element in sequence:
+ try:
+ interpreter.assign(iterator, element, locals)
+ self.subrun(info[0][1], interpreter, locals)
+ except ContinueFlow:
+ continue
+ except BreakFlow:
+ break
+ else:
+ if elseTokens:
+ self.subrun(elseTokens, interpreter, locals)
+ elif self.type == 'while':
+ testCode = self.rest
+ info = self.build(['else'])
+ elseTokens = None
+ if info[-1][0].type == 'else':
+ elseTokens = info.pop()[1]
+ if len(info) != 1:
+ raise ParseError, "control 'while' expects at most one 'else'"
+ atLeastOnce = False
+ while True:
+ try:
+ if not interpreter.evaluate(testCode, locals):
+ break
+ atLeastOnce = True
+ self.subrun(info[0][1], interpreter, locals)
+ except ContinueFlow:
+ continue
+ except BreakFlow:
+ break
+ if not atLeastOnce and elseTokens:
+ self.subrun(elseTokens, interpreter, locals)
+ elif self.type == 'try':
+ info = self.build(['except', 'finally'])
+ if len(info) == 1:
+ raise ParseError, "control 'try' needs 'except' or 'finally'"
+ type = info[-1][0].type
+ if type == 'except':
+ for secondary, _tokens in info[1:]:
+ if secondary.type != 'except':
+ raise ParseError, \
+ "control 'try' cannot have 'except' and 'finally'"
+ else:
+ assert type == 'finally'
+ if len(info) != 2:
+ raise ParseError, \
+ "control 'try' can only have one 'finally'"
+ if type == 'except':
+ try:
+ self.subrun(info[0][1], interpreter, locals)
+ except FlowError:
+ raise
+ except Exception, e:
+ for secondary, tokens in info[1:]:
+ exception, variable = interpreter.clause(secondary.rest)
+ if variable is not None:
+ interpreter.assign(variable, e)
+ if isinstance(e, exception):
+ self.subrun(tokens, interpreter, locals)
+ break
+ else:
+ raise
+ else:
+ try:
+ self.subrun(info[0][1], interpreter, locals)
+ finally:
+ self.subrun(info[1][1], interpreter, locals)
+ elif self.type == 'continue':
+ raise ContinueFlow, "control 'continue' without 'for', 'while'"
+ elif self.type == 'break':
+ raise BreakFlow, "control 'break' without 'for', 'while'"
+ elif self.type == 'def':
+ signature = self.rest
+ definition = self.substring()
+ code = 'def %s:\n' \
+ ' r"""%s"""\n' \
+ ' return %s.expand(r"""%s""", locals())\n' % \
+ (signature, definition, interpreter.pseudo, definition)
+ interpreter.execute(code, locals)
+ elif self.type == 'end':
+ raise ParseError, "control 'end' requires primary markup"
+ else:
+ raise ParseError, \
+ "control '%s' cannot be at this level" % self.type
+ interpreter.invoke('afterControl')
+
+ def subrun(self, tokens, interpreter, locals):
+ """Execute a sequence of tokens."""
+ for token in tokens:
+ token.run(interpreter, locals)
+
+ def substring(self):
+ return string.join(map(str, self.subtokens), '')
+
+ def string(self):
+ if self.kind == 'primary':
+ return '%s[%s]%s%s[end %s]' % \
+ (self.prefix, self.contents, self.substring(), \
+ self.prefix, self.type)
+ else:
+ return '%s[%s]' % (self.prefix, self.contents)
+
+
+class Scanner:
+
+ """A scanner holds a buffer for lookahead parsing and has the
+ ability to scan for special symbols and indicators in that
+ buffer."""
+
+ # This is the token mapping table that maps first characters to
+ # token classes.
+ TOKEN_MAP = [
+ (None, PrefixToken),
+ (' \t\v\r\n', WhitespaceToken),
+ (')]}', LiteralToken),
+ ('\\', EscapeToken),
+ ('#', CommentToken),
+ ('?', ContextNameToken),
+ ('!', ContextLineToken),
+ ('%', SignificatorToken),
+ ('(', ExpressionToken),
+ (IDENTIFIER_FIRST_CHARS, SimpleExpressionToken),
+ ('\'\"', StringLiteralToken),
+ ('`', ReprToken),
+ (':', InPlaceToken),
+ ('[', ControlToken),
+ ('{', StatementToken),
+ ('<', CustomToken),
+ ]
+
+ def __init__(self, prefix, data=''):
+ self.prefix = prefix
+ self.pointer = 0
+ self.buffer = data
+ self.lock = 0
+
+ def __nonzero__(self): return self.pointer < len(self.buffer)
+ def __len__(self): return len(self.buffer) - self.pointer
+ def __getitem__(self, index): return self.buffer[self.pointer + index]
+
+ def __getslice__(self, start, stop):
+ if stop > len(self):
+ stop = len(self)
+ return self.buffer[self.pointer + start:self.pointer + stop]
+
+ def advance(self, count=1):
+ """Advance the pointer count characters."""
+ self.pointer = self.pointer + count
+
+ def retreat(self, count=1):
+ self.pointer = self.pointer - count
+ if self.pointer < 0:
+ raise ParseError, "can't retreat back over synced out chars"
+
+ def set(self, data):
+ """Start the scanner digesting a new batch of data; start the pointer
+ over from scratch."""
+ self.pointer = 0
+ self.buffer = data
+
+ def feed(self, data):
+ """Feed some more data to the scanner."""
+ self.buffer = self.buffer + data
+
+ def chop(self, count=None, slop=0):
+ """Chop the first count + slop characters off the front, and return
+ the first count. If count is not specified, then return
+ everything."""
+ if count is None:
+ assert slop == 0
+ count = len(self)
+ if count > len(self):
+ raise TransientParseError, "not enough data to read"
+ result = self[:count]
+ self.advance(count + slop)
+ return result
+
+ def acquire(self):
+ """Lock the scanner so it doesn't destroy data on sync."""
+ self.lock = self.lock + 1
+
+ def release(self):
+ """Unlock the scanner."""
+ self.lock = self.lock - 1
+
+ def sync(self):
+ """Sync up the buffer with the read head."""
+ if self.lock == 0 and self.pointer != 0:
+ self.buffer = self.buffer[self.pointer:]
+ self.pointer = 0
+
+ def unsync(self):
+ """Undo changes; reset the read head."""
+ if self.pointer != 0:
+ self.lock = 0
+ self.pointer = 0
+
+ def rest(self):
+ """Get the remainder of the buffer."""
+ return self[:]
+
+ def read(self, i=0, count=1):
+ """Read count chars starting from i; raise a transient error if
+ there aren't enough characters remaining."""
+ if len(self) < i + count:
+ raise TransientParseError, "need more data to read"
+ else:
+ return self[i:i + count]
+
+ def check(self, i, archetype=None):
+ """Scan for the next single or triple quote, with the specified
+ archetype. Return the found quote or None."""
+ quote = None
+ if self[i] in '\'\"':
+ quote = self[i]
+ if len(self) - i < 3:
+ for j in range(i, len(self)):
+ if self[i] == quote:
+ return quote
+ else:
+ raise TransientParseError, "need to scan for rest of quote"
+ if self[i + 1] == self[i + 2] == quote:
+ quote = quote * 3
+ if quote is not None:
+ if archetype is None:
+ return quote
+ else:
+ if archetype == quote:
+ return quote
+ elif len(archetype) < len(quote) and archetype[0] == quote[0]:
+ return archetype
+ else:
+ return None
+ else:
+ return None
+
+ def find(self, sub, start=0, end=None):
+ """Find the next occurrence of the character, or return -1."""
+ if end is not None:
+ return string.find(self.rest(), sub, start, end)
+ else:
+ return string.find(self.rest(), sub, start)
+
+ def last(self, char, start=0, end=None):
+ """Find the first character that is _not_ the specified character."""
+ if end is None:
+ end = len(self)
+ i = start
+ while i < end:
+ if self[i] != char:
+ return i
+ i = i + 1
+ else:
+ raise TransientParseError, "expecting other than %s" % char
+
+ def next(self, target, start=0, end=None, mandatory=False):
+ """Scan for the next occurrence of one of the characters in
+ the target string; optionally, make the scan mandatory."""
+ if mandatory:
+ assert end is not None
+ quote = None
+ if end is None:
+ end = len(self)
+ i = start
+ while i < end:
+ newQuote = self.check(i, quote)
+ if newQuote:
+ if newQuote == quote:
+ quote = None
+ else:
+ quote = newQuote
+ i = i + len(newQuote)
+ else:
+ c = self[i]
+ if quote:
+ if c == '\\':
+ i = i + 1
+ else:
+ if c in target:
+ return i
+ i = i + 1
+ else:
+ if mandatory:
+ raise ParseError, "expecting %s, not found" % target
+ else:
+ raise TransientParseError, "expecting ending character"
+
+ def quote(self, start=0, end=None, mandatory=False):
+ """Scan for the end of the next quote."""
+ assert self[start] in '\'\"'
+ quote = self.check(start)
+ if end is None:
+ end = len(self)
+ i = start + len(quote)
+ while i < end:
+ newQuote = self.check(i, quote)
+ if newQuote:
+ i = i + len(newQuote)
+ if newQuote == quote:
+ return i
+ else:
+ c = self[i]
+ if c == '\\':
+ i = i + 1
+ i = i + 1
+ else:
+ if mandatory:
+ raise ParseError, "expecting end of string literal"
+ else:
+ raise TransientParseError, "expecting end of string literal"
+
+ def nested(self, enter, exit, start=0, end=None):
+ """Scan from i for an ending sequence, respecting entries and exits
+ only."""
+ depth = 0
+ if end is None:
+ end = len(self)
+ i = start
+ while i < end:
+ c = self[i]
+ if c == enter:
+ depth = depth + 1
+ elif c == exit:
+ depth = depth - 1
+ if depth < 0:
+ return i
+ i = i + 1
+ else:
+ raise TransientParseError, "expecting end of complex expression"
+
+ def complex(self, enter, exit, start=0, end=None, skip=None):
+ """Scan from i for an ending sequence, respecting quotes,
+ entries and exits."""
+ quote = None
+ depth = 0
+ if end is None:
+ end = len(self)
+ last = None
+ i = start
+ while i < end:
+ newQuote = self.check(i, quote)
+ if newQuote:
+ if newQuote == quote:
+ quote = None
+ else:
+ quote = newQuote
+ i = i + len(newQuote)
+ else:
+ c = self[i]
+ if quote:
+ if c == '\\':
+ i = i + 1
+ else:
+ if skip is None or last != skip:
+ if c == enter:
+ depth = depth + 1
+ elif c == exit:
+ depth = depth - 1
+ if depth < 0:
+ return i
+ last = c
+ i = i + 1
+ else:
+ raise TransientParseError, "expecting end of complex expression"
+
+ def word(self, start=0):
+ """Scan from i for a simple word."""
+ length = len(self)
+ i = start
+ while i < length:
+ if not self[i] in IDENTIFIER_CHARS:
+ return i
+ i = i + 1
+ else:
+ raise TransientParseError, "expecting end of word"
+
+ def phrase(self, start=0):
+ """Scan from i for a phrase (e.g., 'word', 'f(a, b, c)', 'a[i]', or
+ combinations like 'x[i](a)'."""
+ # Find the word.
+ i = self.word(start)
+ while i < len(self) and self[i] in '([{':
+ enter = self[i]
+ if enter == '{':
+ raise ParseError, "curly braces can't open simple expressions"
+ exit = ENDING_CHARS[enter]
+ i = self.complex(enter, exit, i + 1) + 1
+ return i
+
+ def simple(self, start=0):
+ """Scan from i for a simple expression, which consists of one
+ more phrases separated by dots."""
+ i = self.phrase(start)
+ length = len(self)
+ while i < length and self[i] == '.':
+ i = self.phrase(i)
+ # Make sure we don't end with a trailing dot.
+ while i > 0 and self[i - 1] == '.':
+ i = i - 1
+ return i
+
+ def one(self):
+ """Parse and return one token, or None if the scanner is empty."""
+ if not self:
+ return None
+ if not self.prefix:
+ loc = -1
+ else:
+ loc = self.find(self.prefix)
+ if loc < 0:
+ # If there's no prefix in the buffer, then set the location to
+ # the end so the whole thing gets processed.
+ loc = len(self)
+ if loc == 0:
+ # If there's a prefix at the beginning of the buffer, process
+ # an expansion.
+ prefix = self.chop(1)
+ assert prefix == self.prefix
+ first = self.chop(1)
+ if first == self.prefix:
+ first = None
+ for firsts, factory in self.TOKEN_MAP:
+ if firsts is None:
+ if first is None:
+ break
+ elif first in firsts:
+ break
+ else:
+ raise ParseError, "unknown markup: %s%s" % (self.prefix, first)
+ token = factory(self.prefix, first)
+ try:
+ token.scan(self)
+ except TransientParseError:
+ # If a transient parse error occurs, reset the buffer pointer
+ # so we can (conceivably) try again later.
+ self.unsync()
+ raise
+ else:
+ # Process everything up to loc as a null token.
+ data = self.chop(loc)
+ token = NullToken(data)
+ self.sync()
+ return token
+
+
+class Interpreter:
+
+ """An interpreter can process chunks of EmPy code."""
+
+ # Constants.
+
+ VERSION = __version__
+ SIGNIFICATOR_RE_SUFFIX = SIGNIFICATOR_RE_SUFFIX
+ SIGNIFICATOR_RE_STRING = None
+
+ # Types.
+
+ Interpreter = None # define this below to prevent a circular reference
+ Hook = Hook # DEPRECATED
+ Filter = Filter # DEPRECATED
+ NullFilter = NullFilter # DEPRECATED
+ FunctionFilter = FunctionFilter # DEPRECATED
+ StringFilter = StringFilter # DEPRECATED
+ BufferedFilter = BufferedFilter # DEPRECATED
+ SizeBufferedFilter = SizeBufferedFilter # DEPRECATED
+ LineBufferedFilter = LineBufferedFilter # DEPRECATED
+ MaximallyBufferedFilter = MaximallyBufferedFilter # DEPRECATED
+
+ # Tables.
+
+ ESCAPE_CODES = {0x00: '0', 0x07: 'a', 0x08: 'b', 0x1b: 'e', 0x0c: 'f', \
+ 0x7f: 'h', 0x0a: 'n', 0x0d: 'r', 0x09: 't', 0x0b: 'v', \
+ 0x04: 'z'}
+
+ ASSIGN_TOKEN_RE = re.compile(r"[_a-zA-Z][_a-zA-Z0-9]*|\(|\)|,")
+
+ DEFAULT_OPTIONS = {BANGPATH_OPT: True,
+ BUFFERED_OPT: False,
+ RAW_OPT: False,
+ EXIT_OPT: True,
+ FLATTEN_OPT: False,
+ OVERRIDE_OPT: True,
+ CALLBACK_OPT: False}
+
+ _wasProxyInstalled = False # was a proxy installed?
+
+ # Construction, initialization, destruction.
+
+ def __init__(self, output=None, argv=None, prefix=DEFAULT_PREFIX, \
+ pseudo=None, options=None, globals=None, hooks=None):
+ self.interpreter = self # DEPRECATED
+ # Set up the stream.
+ if output is None:
+ output = UncloseableFile(sys.__stdout__)
+ self.output = output
+ self.prefix = prefix
+ if pseudo is None:
+ pseudo = DEFAULT_PSEUDOMODULE_NAME
+ self.pseudo = pseudo
+ if argv is None:
+ argv = [DEFAULT_SCRIPT_NAME]
+ self.argv = argv
+ self.args = argv[1:]
+ if options is None:
+ options = {}
+ self.options = options
+ # Initialize any hooks.
+ self.hooksEnabled = None # special sentinel meaning "false until added"
+ self.hooks = []
+ if hooks is None:
+ hooks = []
+ for hook in hooks:
+ self.register(hook)
+ # Initialize callback.
+ self.callback = None
+ # Finalizers.
+ self.finals = []
+ # The interpreter stacks.
+ self.contexts = Stack()
+ self.streams = Stack()
+ # Now set up the globals.
+ self.globals = globals
+ self.fix()
+ self.history = Stack()
+ # Install a proxy stdout if one hasn't been already.
+ self.installProxy()
+ # Finally, reset the state of all the stacks.
+ self.reset()
+ # Okay, now flatten the namespaces if that option has been set.
+ if self.options.get(FLATTEN_OPT, False):
+ self.flatten()
+ # Set up old pseudomodule attributes.
+ if prefix is None:
+ self.SIGNIFICATOR_RE_STRING = None
+ else:
+ self.SIGNIFICATOR_RE_STRING = prefix + self.SIGNIFICATOR_RE_SUFFIX
+ self.Interpreter = self.__class__
+ # Done. Now declare that we've started up.
+ self.invoke('atStartup')
+
+ def __del__(self):
+ self.shutdown()
+
+ def __repr__(self):
+ return '<%s pseudomodule/interpreter at 0x%x>' % \
+ (self.pseudo, id(self))
+
+ def ready(self):
+ """Declare the interpreter ready for normal operations."""
+ self.invoke('atReady')
+
+ def fix(self):
+ """Reset the globals, stamping in the pseudomodule."""
+ if self.globals is None:
+ self.globals = {}
+ # Make sure that there is no collision between two interpreters'
+ # globals.
+ if self.globals.has_key(self.pseudo):
+ if self.globals[self.pseudo] is not self:
+ raise Error, "interpreter globals collision"
+ self.globals[self.pseudo] = self
+
+ def unfix(self):
+ """Remove the pseudomodule (if present) from the globals."""
+ UNWANTED_KEYS = [self.pseudo, '__builtins__']
+ for unwantedKey in UNWANTED_KEYS:
+ if self.globals.has_key(unwantedKey):
+ del self.globals[unwantedKey]
+
+ def update(self, other):
+ """Update the current globals dictionary with another dictionary."""
+ self.globals.update(other)
+ self.fix()
+
+ def clear(self):
+ """Clear out the globals dictionary with a brand new one."""
+ self.globals = {}
+ self.fix()
+
+ def save(self, deep=True):
+ if deep:
+ copyMethod = copy.deepcopy
+ else:
+ copyMethod = copy.copy
+ """Save a copy of the current globals on the history stack."""
+ self.unfix()
+ self.history.push(copyMethod(self.globals))
+ self.fix()
+
+ def restore(self, destructive=True):
+ """Restore the topmost historic globals."""
+ if destructive:
+ fetchMethod = self.history.pop
+ else:
+ fetchMethod = self.history.top
+ self.unfix()
+ self.globals = fetchMethod()
+ self.fix()
+
+ def shutdown(self):
+ """Declare this interpreting session over; close the stream file
+ object. This method is idempotent."""
+ if self.streams is not None:
+ try:
+ self.finalize()
+ self.invoke('atShutdown')
+ while self.streams:
+ stream = self.streams.pop()
+ stream.close()
+ finally:
+ self.streams = None
+
+ def ok(self):
+ """Is the interpreter still active?"""
+ return self.streams is not None
+
+ # Writeable file-like methods.
+
+ def write(self, data):
+ self.stream().write(data)
+
+ def writelines(self, stuff):
+ self.stream().writelines(stuff)
+
+ def flush(self):
+ self.stream().flush()
+
+ def close(self):
+ self.shutdown()
+
+ # Stack-related activity.
+
+ def context(self):
+ return self.contexts.top()
+
+ def stream(self):
+ return self.streams.top()
+
+ def reset(self):
+ self.contexts.purge()
+ self.streams.purge()
+ self.streams.push(Stream(self.output))
+ if self.options.get(OVERRIDE_OPT, True):
+ sys.stdout.clear(self)
+
+ def push(self):
+ if self.options.get(OVERRIDE_OPT, True):
+ sys.stdout.push(self)
+
+ def pop(self):
+ if self.options.get(OVERRIDE_OPT, True):
+ sys.stdout.pop(self)
+
+ # Higher-level operations.
+
+ def include(self, fileOrFilename, locals=None):
+ """Do an include pass on a file or filename."""
+ if type(fileOrFilename) is types.StringType:
+ # Either it's a string representing a filename ...
+ filename = fileOrFilename
+ name = filename
+ file = theSubsystem.open(filename, 'r')
+ else:
+ # ... or a file object.
+ file = fileOrFilename
+ name = "<%s>" % str(file.__class__)
+ self.invoke('beforeInclude', name=name, file=file, locals=locals)
+ self.file(file, name, locals)
+ self.invoke('afterInclude')
+
+ def expand(self, data, locals=None):
+ """Do an explicit expansion on a subordinate stream."""
+ outFile = StringIO.StringIO()
+ stream = Stream(outFile)
+ self.invoke('beforeExpand', string=data, locals=locals)
+ self.streams.push(stream)
+ try:
+ self.string(data, '<expand>', locals)
+ stream.flush()
+ expansion = outFile.getvalue()
+ self.invoke('afterExpand', result=expansion)
+ return expansion
+ finally:
+ self.streams.pop()
+
+ def quote(self, data):
+ """Quote the given string so that if it were expanded it would
+ evaluate to the original."""
+ self.invoke('beforeQuote', string=data)
+ scanner = Scanner(self.prefix, data)
+ result = []
+ i = 0
+ try:
+ j = scanner.next(self.prefix, i)
+ result.append(data[i:j])
+ result.append(self.prefix * 2)
+ i = j + 1
+ except TransientParseError:
+ pass
+ result.append(data[i:])
+ result = string.join(result, '')
+ self.invoke('afterQuote', result=result)
+ return result
+
+ def escape(self, data, more=''):
+ """Escape a string so that nonprintable characters are replaced
+ with compatible EmPy expansions."""
+ self.invoke('beforeEscape', string=data, more=more)
+ result = []
+ for char in data:
+ if char < ' ' or char > '~':
+ charOrd = ord(char)
+ if Interpreter.ESCAPE_CODES.has_key(charOrd):
+ result.append(self.prefix + '\\' + \
+ Interpreter.ESCAPE_CODES[charOrd])
+ else:
+ result.append(self.prefix + '\\x%02x' % charOrd)
+ elif char in more:
+ result.append(self.prefix + '\\' + char)
+ else:
+ result.append(char)
+ result = string.join(result, '')
+ self.invoke('afterEscape', result=result)
+ return result
+
+ # Processing.
+
+ def wrap(self, callable, args):
+ """Wrap around an application of a callable and handle errors.
+ Return whether no error occurred."""
+ try:
+ apply(callable, args)
+ self.reset()
+ return True
+ except KeyboardInterrupt, e:
+ # Handle keyboard interrupts specially: we should always exit
+ # from these.
+ self.fail(e, True)
+ except Exception, e:
+ # A standard exception (other than a keyboard interrupt).
+ self.fail(e)
+ except:
+ # If we get here, then either it's an exception not derived from
+ # Exception or it's a string exception, so get the error type
+ # from the sys module.
+ e = sys.exc_type
+ self.fail(e)
+ # An error occurred if we leak through to here, so do cleanup.
+ self.reset()
+ return False
+
+ def interact(self):
+ """Perform interaction."""
+ self.invoke('atInteract')
+ done = False
+ while not done:
+ result = self.wrap(self.file, (sys.stdin, '<interact>'))
+ if self.options.get(EXIT_OPT, True):
+ done = True
+ else:
+ if result:
+ done = True
+ else:
+ self.reset()
+
+ def fail(self, error, fatal=False):
+ """Handle an actual error that occurred."""
+ if self.options.get(BUFFERED_OPT, False):
+ try:
+ self.output.abort()
+ except AttributeError:
+ # If the output file object doesn't have an abort method,
+ # something got mismatched, but it's too late to do
+ # anything about it now anyway, so just ignore it.
+ pass
+ meta = self.meta(error)
+ self.handle(meta)
+ if self.options.get(RAW_OPT, False):
+ raise
+ if fatal or self.options.get(EXIT_OPT, True):
+ sys.exit(FAILURE_CODE)
+
+ def file(self, file, name='<file>', locals=None):
+ """Parse the entire contents of a file-like object, line by line."""
+ context = Context(name)
+ self.contexts.push(context)
+ self.invoke('beforeFile', name=name, file=file, locals=locals)
+ scanner = Scanner(self.prefix)
+ first = True
+ done = False
+ while not done:
+ self.context().bump()
+ line = file.readline()
+ if first:
+ if self.options.get(BANGPATH_OPT, True) and self.prefix:
+ # Replace a bangpath at the beginning of the first line
+ # with an EmPy comment.
+ if string.find(line, BANGPATH) == 0:
+ line = self.prefix + '#' + line[2:]
+ first = False
+ if line:
+ scanner.feed(line)
+ else:
+ done = True
+ self.safe(scanner, done, locals)
+ self.invoke('afterFile')
+ self.contexts.pop()
+
+ def binary(self, file, name='<binary>', chunkSize=0, locals=None):
+ """Parse the entire contents of a file-like object, in chunks."""
+ if chunkSize <= 0:
+ chunkSize = DEFAULT_CHUNK_SIZE
+ context = Context(name, units='bytes')
+ self.contexts.push(context)
+ self.invoke('beforeBinary', name=name, file=file, \
+ chunkSize=chunkSize, locals=locals)
+ scanner = Scanner(self.prefix)
+ done = False
+ while not done:
+ chunk = file.read(chunkSize)
+ if chunk:
+ scanner.feed(chunk)
+ else:
+ done = True
+ self.safe(scanner, done, locals)
+ self.context().bump(len(chunk))
+ self.invoke('afterBinary')
+ self.contexts.pop()
+
+ def string(self, data, name='<string>', locals=None):
+ """Parse a string."""
+ context = Context(name)
+ self.contexts.push(context)
+ self.invoke('beforeString', name=name, string=data, locals=locals)
+ context.bump()
+ scanner = Scanner(self.prefix, data)
+ self.safe(scanner, True, locals)
+ self.invoke('afterString')
+ self.contexts.pop()
+
+ def safe(self, scanner, final=False, locals=None):
+ """Do a protected parse. Catch transient parse errors; if
+ final is true, then make a final pass with a terminator,
+ otherwise ignore the transient parse error (more data is
+ pending)."""
+ try:
+ self.parse(scanner, locals)
+ except TransientParseError:
+ if final:
+ # If the buffer doesn't end with a newline, try tacking on
+ # a dummy terminator.
+ buffer = scanner.rest()
+ if buffer and buffer[-1] != '\n':
+ scanner.feed(self.prefix + '\n')
+ # A TransientParseError thrown from here is a real parse
+ # error.
+ self.parse(scanner, locals)
+
+ def parse(self, scanner, locals=None):
+ """Parse and run as much from this scanner as possible."""
+ self.invoke('atParse', scanner=scanner, locals=locals)
+ while True:
+ token = scanner.one()
+ if token is None:
+ break
+ self.invoke('atToken', token=token)
+ token.run(self, locals)
+
+ # Medium-level evaluation and execution.
+
+ def tokenize(self, name):
+ """Take an lvalue string and return a name or a (possibly recursive)
+ list of names."""
+ result = []
+ stack = [result]
+ for garbage in self.ASSIGN_TOKEN_RE.split(name):
+ garbage = string.strip(garbage)
+ if garbage:
+ raise ParseError, "unexpected assignment token: '%s'" % garbage
+ tokens = self.ASSIGN_TOKEN_RE.findall(name)
+ # While processing, put a None token at the start of any list in which
+ # commas actually appear.
+ for token in tokens:
+ if token == '(':
+ stack.append([])
+ elif token == ')':
+ top = stack.pop()
+ if len(top) == 1:
+ top = top[0] # no None token means that it's not a 1-tuple
+ elif top[0] is None:
+ del top[0] # remove the None token for real tuples
+ stack[-1].append(top)
+ elif token == ',':
+ if len(stack[-1]) == 1:
+ stack[-1].insert(0, None)
+ else:
+ stack[-1].append(token)
+ # If it's a 1-tuple at the top level, turn it into a real subsequence.
+ if result and result[0] is None:
+ result = [result[1:]]
+ if len(result) == 1:
+ return result[0]
+ else:
+ return result
+
+ def significate(self, key, value=None, locals=None):
+ """Declare a significator."""
+ self.invoke('beforeSignificate', key=key, value=value, locals=locals)
+ name = '__%s__' % key
+ self.atomic(name, value, locals)
+ self.invoke('afterSignificate')
+
+ def atomic(self, name, value, locals=None):
+ """Do an atomic assignment."""
+ self.invoke('beforeAtomic', name=name, value=value, locals=locals)
+ if locals is None:
+ self.globals[name] = value
+ else:
+ locals[name] = value
+ self.invoke('afterAtomic')
+
+ def multi(self, names, values, locals=None):
+ """Do a (potentially recursive) assignment."""
+ self.invoke('beforeMulti', names=names, values=values, locals=locals)
+ # No zip in 1.5, so we have to do it manually.
+ i = 0
+ try:
+ values = tuple(values)
+ except TypeError:
+ raise TypeError, "unpack non-sequence"
+ if len(names) != len(values):
+ raise ValueError, "unpack tuple of wrong size"
+ for i in range(len(names)):
+ name = names[i]
+ if type(name) is types.StringType:
+ self.atomic(name, values[i], locals)
+ else:
+ self.multi(name, values[i], locals)
+ self.invoke('afterMulti')
+
+ def assign(self, name, value, locals=None):
+ """Do a potentially complex (including tuple unpacking) assignment."""
+ left = self.tokenize(name)
+ # The return value of tokenize can either be a string or a list of
+ # (lists of) strings.
+ if type(left) is types.StringType:
+ self.atomic(left, value, locals)
+ else:
+ self.multi(left, value, locals)
+
+ def import_(self, name, locals=None):
+ """Do an import."""
+ self.invoke('beforeImport', name=name, locals=locals)
+ self.execute('import %s' % name, locals)
+ self.invoke('afterImport')
+
+ def clause(self, catch, locals=None):
+ """Given the string representation of an except clause, turn it into
+ a 2-tuple consisting of the class name, and either a variable name
+ or None."""
+ self.invoke('beforeClause', catch=catch, locals=locals)
+ if catch is None:
+ exceptionCode, variable = None, None
+ elif string.find(catch, ',') >= 0:
+ exceptionCode, variable = string.split(string.strip(catch), ',', 1)
+ variable = string.strip(variable)
+ else:
+ exceptionCode, variable = string.strip(catch), None
+ if not exceptionCode:
+ exception = Exception
+ else:
+ exception = self.evaluate(exceptionCode, locals)
+ self.invoke('afterClause', exception=exception, variable=variable)
+ return exception, variable
+
+ def serialize(self, expression, locals=None):
+ """Do an expansion, involving evaluating an expression, then
+ converting it to a string and writing that string to the
+ output if the evaluation is not None."""
+ self.invoke('beforeSerialize', expression=expression, locals=locals)
+ result = self.evaluate(expression, locals)
+ if result is not None:
+ self.write(str(result))
+ self.invoke('afterSerialize')
+
+ def defined(self, name, locals=None):
+ """Return a Boolean indicating whether or not the name is
+ defined either in the locals or the globals."""
+ self.invoke('beforeDefined', name=name, local=local)
+ if locals is not None:
+ if locals.has_key(name):
+ result = True
+ else:
+ result = False
+ elif self.globals.has_key(name):
+ result = True
+ else:
+ result = False
+ self.invoke('afterDefined', result=result)
+
+ def literal(self, text):
+ """Process a string literal."""
+ self.invoke('beforeLiteral', text=text)
+ self.serialize(text)
+ self.invoke('afterLiteral')
+
+ # Low-level evaluation and execution.
+
+ def evaluate(self, expression, locals=None):
+ """Evaluate an expression."""
+ if expression in ('1', 'True'): return True
+ if expression in ('0', 'False'): return False
+ self.push()
+ try:
+ self.invoke('beforeEvaluate', \
+ expression=expression, locals=locals)
+ if locals is not None:
+ result = eval(expression, self.globals, locals)
+ else:
+ result = eval(expression, self.globals)
+ self.invoke('afterEvaluate', result=result)
+ return result
+ finally:
+ self.pop()
+
+ def execute(self, statements, locals=None):
+ """Execute a statement."""
+ # If there are any carriage returns (as opposed to linefeeds/newlines)
+ # in the statements code, then remove them. Even on DOS/Windows
+ # platforms,
+ if string.find(statements, '\r') >= 0:
+ statements = string.replace(statements, '\r', '')
+ # If there are no newlines in the statements code, then strip any
+ # leading or trailing whitespace.
+ if string.find(statements, '\n') < 0:
+ statements = string.strip(statements)
+ self.push()
+ try:
+ self.invoke('beforeExecute', \
+ statements=statements, locals=locals)
+ if locals is not None:
+ exec statements in self.globals, locals
+ else:
+ exec statements in self.globals
+ self.invoke('afterExecute')
+ finally:
+ self.pop()
+
+ def single(self, source, locals=None):
+ """Execute an expression or statement, just as if it were
+ entered into the Python interactive interpreter."""
+ self.push()
+ try:
+ self.invoke('beforeSingle', \
+ source=source, locals=locals)
+ code = compile(source, '<single>', 'single')
+ if locals is not None:
+ exec code in self.globals, locals
+ else:
+ exec code in self.globals
+ self.invoke('afterSingle')
+ finally:
+ self.pop()
+
+ # Hooks.
+
+ def register(self, hook, prepend=False):
+ """Register the provided hook."""
+ hook.register(self)
+ if self.hooksEnabled is None:
+ # A special optimization so that hooks can be effectively
+ # disabled until one is added or they are explicitly turned on.
+ self.hooksEnabled = True
+ if prepend:
+ self.hooks.insert(0, hook)
+ else:
+ self.hooks.append(hook)
+
+ def deregister(self, hook):
+ """Remove an already registered hook."""
+ hook.deregister(self)
+ self.hooks.remove(hook)
+
+ def invoke(self, _name, **keywords):
+ """Invoke the hook(s) associated with the hook name, should they
+ exist."""
+ if self.hooksEnabled:
+ for hook in self.hooks:
+ hook.push()
+ try:
+ method = getattr(hook, _name)
+ apply(method, (), keywords)
+ finally:
+ hook.pop()
+
+ def finalize(self):
+ """Execute any remaining final routines."""
+ self.push()
+ self.invoke('atFinalize')
+ try:
+ # Pop them off one at a time so they get executed in reverse
+ # order and we remove them as they're executed in case something
+ # bad happens.
+ while self.finals:
+ final = self.finals.pop()
+ final()
+ finally:
+ self.pop()
+
+ # Error handling.
+
+ def meta(self, exc=None):
+ """Construct a MetaError for the interpreter's current state."""
+ return MetaError(self.contexts.clone(), exc)
+
+ def handle(self, meta):
+ """Handle a MetaError."""
+ first = True
+ self.invoke('atHandle', meta=meta)
+ for context in meta.contexts:
+ if first:
+ if meta.exc is not None:
+ desc = "error: %s: %s" % (meta.exc.__class__, meta.exc)
+ else:
+ desc = "error"
+ else:
+ desc = "from this context"
+ first = False
+ sys.stderr.write('%s: %s\n' % (context, desc))
+
+ def installProxy(self):
+ """Install a proxy if necessary."""
+ # Unfortunately, there's no surefire way to make sure that installing
+ # a sys.stdout proxy is idempotent, what with different interpreters
+ # running from different modules. The best we can do here is to try
+ # manipulating the proxy's test function ...
+ try:
+ sys.stdout._testProxy()
+ except AttributeError:
+ # ... if the current stdout object doesn't have one, then check
+ # to see if we think _this_ particularly Interpreter class has
+ # installed it before ...
+ if Interpreter._wasProxyInstalled:
+ # ... and if so, we have a proxy problem.
+ raise Error, "interpreter stdout proxy lost"
+ else:
+ # Otherwise, install the proxy and set the flag.
+ sys.stdout = ProxyFile(sys.stdout)
+ Interpreter._wasProxyInstalled = True
+
+ #
+ # Pseudomodule routines.
+ #
+
+ # Identification.
+
+ def identify(self):
+ """Identify the topmost context with a 2-tuple of the name and
+ line number."""
+ return self.context().identify()
+
+ def atExit(self, callable):
+ """Register a function to be called at exit."""
+ self.finals.append(callable)
+
+ # Context manipulation.
+
+ def pushContext(self, name='<unnamed>', line=0):
+ """Create a new context and push it."""
+ self.contexts.push(Context(name, line))
+
+ def popContext(self):
+ """Pop the top context."""
+ self.contexts.pop()
+
+ def setContextName(self, name):
+ """Set the name of the topmost context."""
+ context = self.context()
+ context.name = name
+
+ def setContextLine(self, line):
+ """Set the name of the topmost context."""
+ context = self.context()
+ context.line = line
+
+ setName = setContextName # DEPRECATED
+ setLine = setContextLine # DEPRECATED
+
+ # Globals manipulation.
+
+ def getGlobals(self):
+ """Retrieve the globals."""
+ return self.globals
+
+ def setGlobals(self, globals):
+ """Set the globals to the specified dictionary."""
+ self.globals = globals
+ self.fix()
+
+ def updateGlobals(self, otherGlobals):
+ """Merge another mapping object into this interpreter's globals."""
+ self.update(otherGlobals)
+
+ def clearGlobals(self):
+ """Clear out the globals with a brand new dictionary."""
+ self.clear()
+
+ def saveGlobals(self, deep=True):
+ """Save a copy of the globals off onto the history stack."""
+ self.save(deep)
+
+ def restoreGlobals(self, destructive=True):
+ """Restore the most recently saved copy of the globals."""
+ self.restore(destructive)
+
+ # Hook support.
+
+ def areHooksEnabled(self):
+ """Return whether or not hooks are presently enabled."""
+ if self.hooksEnabled is None:
+ return True
+ else:
+ return self.hooksEnabled
+
+ def enableHooks(self):
+ """Enable hooks."""
+ self.hooksEnabled = True
+
+ def disableHooks(self):
+ """Disable hooks."""
+ self.hooksEnabled = False
+
+ def getHooks(self):
+ """Get the current hooks."""
+ return self.hooks[:]
+
+ def clearHooks(self):
+ """Clear all hooks."""
+ self.hooks = []
+
+ def addHook(self, hook, prepend=False):
+ """Add a new hook; optionally insert it rather than appending it."""
+ self.register(hook, prepend)
+
+ def removeHook(self, hook):
+ """Remove a preexisting hook."""
+ self.deregister(hook)
+
+ def invokeHook(self, _name, **keywords):
+ """Manually invoke a hook."""
+ apply(self.invoke, (_name,), keywords)
+
+ # Callbacks.
+
+ def getCallback(self):
+ """Get the callback registered with this interpreter, or None."""
+ return self.callback
+
+ def registerCallback(self, callback):
+ """Register a custom markup callback with this interpreter."""
+ self.callback = callback
+
+ def deregisterCallback(self):
+ """Remove any previously registered callback with this interpreter."""
+ self.callback = None
+
+ def invokeCallback(self, contents):
+ """Invoke the callback."""
+ if self.callback is None:
+ if self.options.get(CALLBACK_OPT, False):
+ raise Error, "custom markup invoked with no defined callback"
+ else:
+ self.callback(contents)
+
+ # Pseudomodule manipulation.
+
+ def flatten(self, keys=None):
+ """Flatten the contents of the pseudo-module into the globals
+ namespace."""
+ if keys is None:
+ keys = self.__dict__.keys() + self.__class__.__dict__.keys()
+ dict = {}
+ for key in keys:
+ # The pseudomodule is really a class instance, so we need to
+ # fumble use getattr instead of simply fumbling through the
+ # instance's __dict__.
+ dict[key] = getattr(self, key)
+ # Stomp everything into the globals namespace.
+ self.globals.update(dict)
+
+ # Prefix.
+
+ def getPrefix(self):
+ """Get the current prefix."""
+ return self.prefix
+
+ def setPrefix(self, prefix):
+ """Set the prefix."""
+ self.prefix = prefix
+
+ # Diversions.
+
+ def stopDiverting(self):
+ """Stop any diverting."""
+ self.stream().revert()
+
+ def createDiversion(self, name):
+ """Create a diversion (but do not divert to it) if it does not
+ already exist."""
+ self.stream().create(name)
+
+ def retrieveDiversion(self, name):
+ """Retrieve the diversion object associated with the name."""
+ return self.stream().retrieve(name)
+
+ def startDiversion(self, name):
+ """Start diverting to the given diversion name."""
+ self.stream().divert(name)
+
+ def playDiversion(self, name):
+ """Play the given diversion and then purge it."""
+ self.stream().undivert(name, True)
+
+ def replayDiversion(self, name):
+ """Replay the diversion without purging it."""
+ self.stream().undivert(name, False)
+
+ def purgeDiversion(self, name):
+ """Eliminate the given diversion."""
+ self.stream().purge(name)
+
+ def playAllDiversions(self):
+ """Play all existing diversions and then purge them."""
+ self.stream().undivertAll(True)
+
+ def replayAllDiversions(self):
+ """Replay all existing diversions without purging them."""
+ self.stream().undivertAll(False)
+
+ def purgeAllDiversions(self):
+ """Purge all existing diversions."""
+ self.stream().purgeAll()
+
+ def getCurrentDiversion(self):
+ """Get the name of the current diversion."""
+ return self.stream().currentDiversion
+
+ def getAllDiversions(self):
+ """Get the names of all existing diversions."""
+ names = self.stream().diversions.keys()
+ names.sort()
+ return names
+
+ # Filter.
+
+ def resetFilter(self):
+ """Reset the filter so that it does no filtering."""
+ self.stream().install(None)
+
+ def nullFilter(self):
+ """Install a filter that will consume all text."""
+ self.stream().install(0)
+
+ def getFilter(self):
+ """Get the current filter."""
+ filter = self.stream().filter
+ if filter is self.stream().file:
+ return None
+ else:
+ return filter
+
+ def setFilter(self, shortcut):
+ """Set the filter."""
+ self.stream().install(shortcut)
+
+ def attachFilter(self, shortcut):
+ """Attach a single filter to the end of the current filter chain."""
+ self.stream().attach(shortcut)
+
+
+class Document:
+
+ """A representation of an individual EmPy document, as used by a
+ processor."""
+
+ def __init__(self, ID, filename):
+ self.ID = ID
+ self.filename = filename
+ self.significators = {}
+
+
+class Processor:
+
+ """An entity which is capable of processing a hierarchy of EmPy
+ files and building a dictionary of document objects associated
+ with them describing their significator contents."""
+
+ DEFAULT_EMPY_EXTENSIONS = ('.em',)
+ SIGNIFICATOR_RE = re.compile(SIGNIFICATOR_RE_STRING)
+
+ def __init__(self, factory=Document):
+ self.factory = factory
+ self.documents = {}
+
+ def identifier(self, pathname, filename): return filename
+
+ def clear(self):
+ self.documents = {}
+
+ def scan(self, basename, extensions=DEFAULT_EMPY_EXTENSIONS):
+ if type(extensions) is types.StringType:
+ extensions = (extensions,)
+ def _noCriteria(x):
+ return True
+ def _extensionsCriteria(pathname, extensions=extensions):
+ if extensions:
+ for extension in extensions:
+ if pathname[-len(extension):] == extension:
+ return True
+ return False
+ else:
+ return True
+ self.directory(basename, _noCriteria, _extensionsCriteria, None)
+ self.postprocess()
+
+ def postprocess(self):
+ pass
+
+ def directory(self, basename, dirCriteria, fileCriteria, depth=None):
+ if depth is not None:
+ if depth <= 0:
+ return
+ else:
+ depth = depth - 1
+ filenames = os.listdir(basename)
+ for filename in filenames:
+ pathname = os.path.join(basename, filename)
+ if os.path.isdir(pathname):
+ if dirCriteria(pathname):
+ self.directory(pathname, dirCriteria, fileCriteria, depth)
+ elif os.path.isfile(pathname):
+ if fileCriteria(pathname):
+ documentID = self.identifier(pathname, filename)
+ document = self.factory(documentID, pathname)
+ self.file(document, open(pathname))
+ self.documents[documentID] = document
+
+ def file(self, document, file):
+ while True:
+ line = file.readline()
+ if not line:
+ break
+ self.line(document, line)
+
+ def line(self, document, line):
+ match = self.SIGNIFICATOR_RE.search(line)
+ if match:
+ key, valueS = match.groups()
+ valueS = string.strip(valueS)
+ if valueS:
+ value = eval(valueS)
+ else:
+ value = None
+ document.significators[key] = value
+
+
+def expand(_data, _globals=None, \
+ _argv=None, _prefix=DEFAULT_PREFIX, _pseudo=None, _options=None, \
+ **_locals):
+ """Do an atomic expansion of the given source data, creating and
+ shutting down an interpreter dedicated to the task. The sys.stdout
+ object is saved off and then replaced before this function
+ returns."""
+ if len(_locals) == 0:
+ # If there were no keyword arguments specified, don't use a locals
+ # dictionary at all.
+ _locals = None
+ output = NullFile()
+ interpreter = Interpreter(output, argv=_argv, prefix=_prefix, \
+ pseudo=_pseudo, options=_options, \
+ globals=_globals)
+ if interpreter.options.get(OVERRIDE_OPT, True):
+ oldStdout = sys.stdout
+ try:
+ result = interpreter.expand(_data, _locals)
+ finally:
+ interpreter.shutdown()
+ if _globals is not None:
+ interpreter.unfix() # remove pseudomodule to prevent clashes
+ if interpreter.options.get(OVERRIDE_OPT, True):
+ sys.stdout = oldStdout
+ return result
+
+def environment(name, default=None):
+ """Get data from the current environment. If the default is True
+ or False, then presume that we're only interested in the existence
+ or non-existence of the environment variable."""
+ if os.environ.has_key(name):
+ # Do the True/False test by value for future compatibility.
+ if default == False or default == True:
+ return True
+ else:
+ return os.environ[name]
+ else:
+ return default
+
+def info(table):
+ DEFAULT_LEFT = 28
+ maxLeft = 0
+ maxRight = 0
+ for left, right in table:
+ if len(left) > maxLeft:
+ maxLeft = len(left)
+ if len(right) > maxRight:
+ maxRight = len(right)
+ FORMAT = ' %%-%ds %%s\n' % max(maxLeft, DEFAULT_LEFT)
+ for left, right in table:
+ if right.find('\n') >= 0:
+ for right in right.split('\n'):
+ sys.stderr.write(FORMAT % (left, right))
+ left = ''
+ else:
+ sys.stderr.write(FORMAT % (left, right))
+
+def usage(verbose=True):
+ """Print usage information."""
+ programName = sys.argv[0]
+ def warn(line=''):
+ sys.stderr.write("%s\n" % line)
+ warn("""\
+Usage: %s [options] [<filename, or '-' for stdin> [<argument>...]]
+Welcome to EmPy version %s.""" % (programName, __version__))
+ warn()
+ warn("Valid options:")
+ info(OPTION_INFO)
+ if verbose:
+ warn()
+ warn("The following markups are supported:")
+ info(MARKUP_INFO)
+ warn()
+ warn("Valid escape sequences are:")
+ info(ESCAPE_INFO)
+ warn()
+ warn("The %s pseudomodule contains the following attributes:" % \
+ DEFAULT_PSEUDOMODULE_NAME)
+ info(PSEUDOMODULE_INFO)
+ warn()
+ warn("The following environment variables are recognized:")
+ info(ENVIRONMENT_INFO)
+ warn()
+ warn(USAGE_NOTES)
+ else:
+ warn()
+ warn("Type %s -H for more extensive help." % programName)
+
+def invoke(args):
+ """Run a standalone instance of an EmPy interpeter."""
+ # Initialize the options.
+ _output = None
+ _options = {BUFFERED_OPT: environment(BUFFERED_ENV, False),
+ RAW_OPT: environment(RAW_ENV, False),
+ EXIT_OPT: True,
+ FLATTEN_OPT: environment(FLATTEN_ENV, False),
+ OVERRIDE_OPT: not environment(NO_OVERRIDE_ENV, False),
+ CALLBACK_OPT: False}
+ _preprocessing = []
+ _prefix = environment(PREFIX_ENV, DEFAULT_PREFIX)
+ _pseudo = environment(PSEUDO_ENV, None)
+ _interactive = environment(INTERACTIVE_ENV, False)
+ _extraArguments = environment(OPTIONS_ENV)
+ _binary = -1 # negative for not, 0 for default size, positive for size
+ _unicode = environment(UNICODE_ENV, False)
+ _unicodeInputEncoding = environment(INPUT_ENCODING_ENV, None)
+ _unicodeOutputEncoding = environment(OUTPUT_ENCODING_ENV, None)
+ _unicodeInputErrors = environment(INPUT_ERRORS_ENV, None)
+ _unicodeOutputErrors = environment(OUTPUT_ERRORS_ENV, None)
+ _hooks = []
+ _pauseAtEnd = False
+ _relativePath = False
+ if _extraArguments is not None:
+ _extraArguments = string.split(_extraArguments)
+ args = _extraArguments + args
+ # Parse the arguments.
+ pairs, remainder = getopt.getopt(args, 'VhHvkp:m:frino:a:buBP:I:D:E:F:', ['version', 'help', 'extended-help', 'verbose', 'null-hook', 'suppress-errors', 'prefix=', 'no-prefix', 'module=', 'flatten', 'raw-errors', 'interactive', 'no-override-stdout', 'binary', 'chunk-size=', 'output=' 'append=', 'preprocess=', 'import=', 'define=', 'execute=', 'execute-file=', 'buffered-output', 'pause-at-end', 'relative-path', 'no-callback-error', 'no-bangpath-processing', 'unicode', 'unicode-encoding=', 'unicode-input-encoding=', 'unicode-output-encoding=', 'unicode-errors=', 'unicode-input-errors=', 'unicode-output-errors='])
+ for option, argument in pairs:
+ if option in ('-V', '--version'):
+ sys.stderr.write("%s version %s\n" % (__program__, __version__))
+ return
+ elif option in ('-h', '--help'):
+ usage(False)
+ return
+ elif option in ('-H', '--extended-help'):
+ usage(True)
+ return
+ elif option in ('-v', '--verbose'):
+ _hooks.append(VerboseHook())
+ elif option in ('--null-hook',):
+ _hooks.append(Hook())
+ elif option in ('-k', '--suppress-errors'):
+ _options[EXIT_OPT] = False
+ _interactive = True # suppress errors implies interactive mode
+ elif option in ('-m', '--module'):
+ _pseudo = argument
+ elif option in ('-f', '--flatten'):
+ _options[FLATTEN_OPT] = True
+ elif option in ('-p', '--prefix'):
+ _prefix = argument
+ elif option in ('--no-prefix',):
+ _prefix = None
+ elif option in ('-r', '--raw-errors'):
+ _options[RAW_OPT] = True
+ elif option in ('-i', '--interactive'):
+ _interactive = True
+ elif option in ('-n', '--no-override-stdout'):
+ _options[OVERRIDE_OPT] = False
+ elif option in ('-o', '--output'):
+ _output = argument, 'w', _options[BUFFERED_OPT]
+ elif option in ('-a', '--append'):
+ _output = argument, 'a', _options[BUFFERED_OPT]
+ elif option in ('-b', '--buffered-output'):
+ _options[BUFFERED_OPT] = True
+ elif option in ('-B',): # DEPRECATED
+ _options[BUFFERED_OPT] = True
+ elif option in ('--binary',):
+ _binary = 0
+ elif option in ('--chunk-size',):
+ _binary = int(argument)
+ elif option in ('-P', '--preprocess'):
+ _preprocessing.append(('pre', argument))
+ elif option in ('-I', '--import'):
+ for module in string.split(argument, ','):
+ module = string.strip(module)
+ _preprocessing.append(('import', module))
+ elif option in ('-D', '--define'):
+ _preprocessing.append(('define', argument))
+ elif option in ('-E', '--execute'):
+ _preprocessing.append(('exec', argument))
+ elif option in ('-F', '--execute-file'):
+ _preprocessing.append(('file', argument))
+ elif option in ('-u', '--unicode'):
+ _unicode = True
+ elif option in ('--pause-at-end',):
+ _pauseAtEnd = True
+ elif option in ('--relative-path',):
+ _relativePath = True
+ elif option in ('--no-callback-error',):
+ _options[CALLBACK_OPT] = True
+ elif option in ('--no-bangpath-processing',):
+ _options[BANGPATH_OPT] = False
+ elif option in ('--unicode-encoding',):
+ _unicodeInputEncoding = _unicodeOutputEncoding = argument
+ elif option in ('--unicode-input-encoding',):
+ _unicodeInputEncoding = argument
+ elif option in ('--unicode-output-encoding',):
+ _unicodeOutputEncoding = argument
+ elif option in ('--unicode-errors',):
+ _unicodeInputErrors = _unicodeOutputErrors = argument
+ elif option in ('--unicode-input-errors',):
+ _unicodeInputErrors = argument
+ elif option in ('--unicode-output-errors',):
+ _unicodeOutputErrors = argument
+ # Set up the Unicode subsystem if required.
+ if _unicode or \
+ _unicodeInputEncoding or _unicodeOutputEncoding or \
+ _unicodeInputErrors or _unicodeOutputErrors:
+ theSubsystem.initialize(_unicodeInputEncoding, \
+ _unicodeOutputEncoding, \
+ _unicodeInputErrors, _unicodeOutputErrors)
+ # Now initialize the output file if something has already been selected.
+ if _output is not None:
+ _output = apply(AbstractFile, _output)
+ # Set up the main filename and the argument.
+ if not remainder:
+ remainder.append('-')
+ filename, arguments = remainder[0], remainder[1:]
+ # Set up the interpreter.
+ if _options[BUFFERED_OPT] and _output is None:
+ raise ValueError, "-b only makes sense with -o or -a arguments"
+ if _prefix == 'None':
+ _prefix = None
+ if _prefix and type(_prefix) is types.StringType and len(_prefix) != 1:
+ raise Error, "prefix must be single-character string"
+ interpreter = Interpreter(output=_output, \
+ argv=remainder, \
+ prefix=_prefix, \
+ pseudo=_pseudo, \
+ options=_options, \
+ hooks=_hooks)
+ try:
+ # Execute command-line statements.
+ i = 0
+ for which, thing in _preprocessing:
+ if which == 'pre':
+ command = interpreter.file
+ target = theSubsystem.open(thing, 'r')
+ name = thing
+ elif which == 'define':
+ command = interpreter.string
+ if string.find(thing, '=') >= 0:
+ target = '%s{%s}' % (_prefix, thing)
+ else:
+ target = '%s{%s = None}' % (_prefix, thing)
+ name = '<define:%d>' % i
+ elif which == 'exec':
+ command = interpreter.string
+ target = '%s{%s}' % (_prefix, thing)
+ name = '<exec:%d>' % i
+ elif which == 'file':
+ command = interpreter.string
+ name = '<file:%d (%s)>' % (i, thing)
+ target = '%s{execfile("""%s""")}' % (_prefix, thing)
+ elif which == 'import':
+ command = interpreter.string
+ name = '<import:%d>' % i
+ target = '%s{import %s}' % (_prefix, thing)
+ else:
+ assert 0
+ interpreter.wrap(command, (target, name))
+ i = i + 1
+ # Now process the primary file.
+ interpreter.ready()
+ if filename == '-':
+ if not _interactive:
+ name = '<stdin>'
+ path = ''
+ file = sys.stdin
+ else:
+ name, file = None, None
+ else:
+ name = filename
+ file = theSubsystem.open(filename, 'r')
+ path = os.path.split(filename)[0]
+ if _relativePath:
+ sys.path.insert(0, path)
+ if file is not None:
+ if _binary < 0:
+ interpreter.wrap(interpreter.file, (file, name))
+ else:
+ chunkSize = _binary
+ interpreter.wrap(interpreter.binary, (file, name, chunkSize))
+ # If we're supposed to go interactive afterwards, do it.
+ if _interactive:
+ interpreter.interact()
+ finally:
+ interpreter.shutdown()
+ # Finally, if we should pause at the end, do it.
+ if _pauseAtEnd:
+ try:
+ raw_input()
+ except EOFError:
+ pass
+
+def main():
+ invoke(sys.argv[1:])
+
+if __name__ == '__main__': main()
diff --git a/shell/data/gtkrc.em b/shell/data/gtkrc.em
new file mode 100644
index 0000000..d4e1a7c
--- /dev/null
+++ b/shell/data/gtkrc.em
@@ -0,0 +1,12 @@
+@{
+if scaling == '72':
+ icon_sizes = 'gtk-large-toolbar=40,40'
+else:
+ icon_sizes = 'gtk-large-toolbar=55,55'
+}@
+gtk-theme-name = "sugar-@scaling"
+gtk-icon-theme-name = "sugar"
+gtk-cursor-theme-name = "sugar"
+gtk-toolbar-style = GTK_TOOLBAR_ICONS
+gtk-icon-sizes = "@icon_sizes"
+gtk-cursor-blink-timeout = 3
diff --git a/shell/data/icons/Makefile.am b/shell/data/icons/Makefile.am
new file mode 100644
index 0000000..a35643a
--- /dev/null
+++ b/shell/data/icons/Makefile.am
@@ -0,0 +1,15 @@
+sugardir = $(pkgdatadir)/data/icons
+
+sugar_DATA = \
+ module-about_me.svg \
+ module-about_my_computer.svg \
+ module-date_and_time.svg \
+ module-frame.svg \
+ module-keyboard.svg \
+ module-language.svg \
+ module-modemconfiguration.svg \
+ module-network.svg \
+ module-power.svg \
+ module-updater.svg
+
+EXTRA_DIST = $(sugar_DATA)
diff --git a/shell/data/icons/module-about_me.svg b/shell/data/icons/module-about_me.svg
new file mode 100644
index 0000000..7abe926
--- /dev/null
+++ b/shell/data/icons/module-about_me.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-about_x5F_me_1_">
+ <path d="M33.359,35.101L43.46,45.201c0.752,0.75,1.217,1.784,1.217,2.932 c0,2.287-1.855,4.143-4.146,4.143c-1.145,0-2.178-0.463-2.932-1.211L27.498,40.963l-10.1,10.1c-0.75,0.75-1.787,1.211-2.933,1.211 c-2.285,0-4.143-1.854-4.143-4.141c0-1.146,0.465-2.184,1.212-2.934l10.104-10.101L11.535,24.997 c-0.747-0.749-1.212-1.785-1.212-2.93c0-2.289,1.854-4.145,4.146-4.145c1.143,0,2.18,0.465,2.93,1.214l10.099,10.101l10.101-10.102 c0.754-0.749,1.787-1.214,2.934-1.214c2.289,0,4.146,1.856,4.146,4.145c0,1.145-0.467,2.179-1.217,2.93L33.359,35.101z" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5"/>
+ <circle cx="27.497" cy="10.849" fill="&fill_color;" r="8.122" stroke="&stroke_color;" stroke-width="3.5"/>
+</g></svg> \ No newline at end of file
diff --git a/shell/data/icons/module-about_my_computer.svg b/shell/data/icons/module-about_my_computer.svg
new file mode 100644
index 0000000..cf3528e
--- /dev/null
+++ b/shell/data/icons/module-about_my_computer.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-about_x5F_my_x5F_xo_1_">
+ <path d="M52.957,40.602h0.002l-0.025-0.017 c-0.152-0.11-0.315-0.21-0.483-0.302l-12.204-7.605V8.667c0-1.624-1.316-2.943-2.941-2.943H6.291c-1.625,0-2.942,1.319-2.942,2.943 V35.08c0,1.1,0.61,2.045,1.503,2.551l-0.019,0.004L19.49,46.77c0.694,0.436,1.534,0.691,2.438,0.691h28.319 c2.362,0,4.296-1.74,4.296-3.865C54.543,42.391,53.923,41.312,52.957,40.602z M9.072,12.392c0-0.619,0.506-1.124,1.124-1.124H33.4 c0.617,0,1.123,0.505,1.123,1.124v16.561c0,0.617-0.506,1.126-1.123,1.126H10.196c-0.617,0-1.124-0.509-1.124-1.126V12.392z" display="inline" fill="&fill_color;" id="module-about_x5F_my_x5F_xo"/>
+</g></svg> \ No newline at end of file
diff --git a/shell/data/icons/module-date_and_time.svg b/shell/data/icons/module-date_and_time.svg
new file mode 100644
index 0000000..605dbeb
--- /dev/null
+++ b/shell/data/icons/module-date_and_time.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-date_x5F_and_x5F_time">
+ <g display="inline">
+ <defs>
+ <path d="M29.891,31.641h17.255c0.346-1.563,0.534-3.187,0.534-4.854c0-12.35-10.013-22.362-22.362-22.362 c-12.351,0-22.362,10.012-22.362,22.362c0,12.351,10.011,22.362,22.362,22.362c1.567,0,3.097-0.163,4.573-0.47V31.641z M26.286,28.242c-0.034,0.022-0.071,0.038-0.107,0.058c-0.064,0.037-0.127,0.075-0.196,0.104 c-0.039,0.016-0.079,0.023-0.118,0.036c-0.069,0.023-0.138,0.049-0.21,0.062c-0.048,0.01-0.098,0.01-0.147,0.015 c-0.063,0.007-0.126,0.02-0.191,0.02c-0.071,0-0.139-0.013-0.208-0.021c-0.043-0.006-0.086-0.005-0.129-0.014 c-0.078-0.015-0.152-0.041-0.226-0.066c-0.034-0.012-0.069-0.019-0.102-0.032c-0.077-0.031-0.147-0.072-0.217-0.113 c-0.028-0.017-0.059-0.028-0.086-0.047c-0.193-0.129-0.359-0.294-0.487-0.487c-0.028-0.042-0.047-0.086-0.071-0.13 c-0.031-0.057-0.065-0.111-0.09-0.171c-0.023-0.056-0.037-0.115-0.054-0.173c-0.015-0.051-0.035-0.101-0.045-0.153 c-0.023-0.114-0.035-0.229-0.035-0.344V10.349c0-0.966,0.783-1.75,1.75-1.75s1.75,0.784,1.75,1.75v12.212l3.973-3.973 c0.684-0.683,1.792-0.683,2.476,0c0.683,0.683,0.683,1.792,0,2.475l-6.96,6.96c-0.001,0.002-0.003,0.003-0.005,0.004 C26.469,28.107,26.381,28.179,26.286,28.242z" id="SVGID_5_"/>
+ </defs>
+ <clipPath id="SVGID_6_">
+ <use overflow="visible" xlink:href="#SVGID_5_"/>
+ </clipPath>
+ <circle clip-path="url(#SVGID_6_)" cx="25.318" cy="26.786" fill="&fill_color;" r="22.362"/>
+ </g>
+ <rect display="inline" fill="none" height="19.319" stroke="&fill_color;" stroke-width="2" width="21.064" x="29.891" y="31.641"/>
+ <g display="inline">
+ <path d="M39.056,44.155c0.527,0,0.936,0.239,0.936,0.792c0,0.551-0.408,0.791-0.864,0.791h-4.006 c-0.527,0-0.936-0.24-0.936-0.791c0-0.252,0.156-0.469,0.276-0.612c0.995-1.188,2.075-2.267,2.986-3.586 c0.216-0.312,0.42-0.684,0.42-1.115c0-0.491-0.372-0.924-0.863-0.924c-1.38,0-0.72,1.943-1.871,1.943 c-0.575,0-0.876-0.408-0.876-0.876c0-1.511,1.344-2.723,2.818-2.723c1.476,0,2.663,0.972,2.663,2.495 c0,1.667-1.858,3.322-2.878,4.605H39.056z" fill="&fill_color;"/>
+ <path d="M46.339,39.25c0,0.756-0.323,1.415-0.983,1.835c0.863,0.396,1.463,1.199,1.463,2.146 c0,1.439-1.318,2.651-3.021,2.651c-1.775,0-2.879-1.309-2.879-2.256c0-0.467,0.492-0.803,0.924-0.803 c0.815,0,0.623,1.402,1.979,1.402c0.623,0,1.127-0.479,1.127-1.115c0-1.679-2.039-0.443-2.039-1.858 c0-1.259,1.703-0.408,1.703-1.739c0-0.455-0.323-0.804-0.863-0.804c-1.139,0-0.982,1.176-1.799,1.176 c-0.492,0-0.779-0.444-0.779-0.888c0-0.936,1.283-1.943,2.614-1.943C45.512,37.055,46.339,38.314,46.339,39.25z" fill="&fill_color;"/>
+ </g>
+</g></svg> \ No newline at end of file
diff --git a/shell/data/icons/module-frame.svg b/shell/data/icons/module-frame.svg
new file mode 100644
index 0000000..11ccee4
--- /dev/null
+++ b/shell/data/icons/module-frame.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-frame">
+ <g display="inline">
+ <g>
+ <path d="M2.934,8.664v38.209h49.391V8.664H2.934z M49.115,43.833H6.144V11.704h42.971V43.833z" fill="&fill_color;"/>
+ </g>
+ </g>
+ <g display="inline" id="Left_Pointer_1_">
+ <path d="M12.533,16.981l-2.359-2.359h1.597c0.2,0,0.401-0.077,0.555-0.23c0.307-0.306,0.307-0.804,0-1.11 c-0.153-0.154-0.355-0.23-0.555-0.231H7.49l0.001,4.28c0,0.201,0.076,0.401,0.23,0.555c0.306,0.307,0.804,0.307,1.111,0 c0.154-0.153,0.229-0.354,0.229-0.555v-1.597l2.36,2.358c0.142,0.142,0.338,0.23,0.556,0.23c0.434,0,0.785-0.353,0.785-0.786 C12.763,17.319,12.674,17.123,12.533,16.981z" fill="&fill_color;"/>
+ </g>
+</g></svg>
diff --git a/shell/data/icons/module-keyboard.svg b/shell/data/icons/module-keyboard.svg
new file mode 100644
index 0000000..43bbc57
--- /dev/null
+++ b/shell/data/icons/module-keyboard.svg
@@ -0,0 +1,134 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-keyboard">
+ <rect display="inline" fill="&fill_color;" height="23.326" width="54" x="0.5" y="15.837"/>
+ <g display="inline">
+ <path d="M52.61,28.081c0,0.55-0.45,1-1,1h-5.443c-0.55,0-1-0.45-1-1v-5.444c0-0.55,0.45-1,1-1h5.443c0.55,0,1,0.45,1,1V28.081z"/>
+ </g>
+ <g display="inline">
+ <path d="M52.61,19.941c0,0.55-0.45,1-1,1h-5.412c-0.55,0-1-0.45-1-1v-1.368c0-0.55,0.45-1,1-1h5.412c0.55,0,1,0.45,1,1V19.941z"/>
+ </g>
+ <g display="inline">
+ <path d="M52.61,32.267c0,0.55-0.45,1-1,1h-5.412c-0.55,0-1-0.45-1-1v-1.367c0-0.55,0.45-1,1-1h5.412c0.55,0,1,0.45,1,1V32.267z"/>
+ </g>
+ <g display="inline">
+ <path d="M39.11,36.403c0,0.55-0.45,1-1,1H13.176c-0.55,0-1-0.45-1-1v-1.366c0-0.55,0.45-1,1-1H38.11c0.55,0,1,0.45,1,1V36.403z"/>
+ </g>
+ <g display="inline">
+ <g>
+ <path d="M5.889,19.977c0,0.55-0.45,1-1,1H3.549c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M10.65,19.977c0,0.55-0.45,1-1,1H8.311c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1H9.65c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M15.411,19.977c0,0.55-0.45,1-1,1h-1.339c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M20.173,19.978c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V19.978z"/>
+ </g>
+ <g>
+ <path d="M24.934,19.977c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M29.695,19.978c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V19.978z"/>
+ </g>
+ <g>
+ <path d="M34.457,19.977c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M39.218,19.977c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ <g>
+ <path d="M43.979,19.977c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V19.977z"/>
+ </g>
+ </g>
+ <g display="inline">
+ <g>
+ <path d="M5.889,24.038c0,0.55-0.45,1-1,1H3.549c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M10.65,24.038c0,0.55-0.45,1-1,1H8.311c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1H9.65c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M15.411,24.038c0,0.55-0.45,1-1,1h-1.339c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M20.173,24.038c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M24.934,24.038c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M29.695,24.038c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M34.457,24.038c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M39.218,24.038c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ <g>
+ <path d="M43.979,24.038c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.339c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V24.038z"/>
+ </g>
+ </g>
+ <g display="inline">
+ <g>
+ <path d="M5.889,28.099c0,0.55-0.45,1-1,1.001H3.549c-0.55,0.001-1-0.449-1-0.999V26.76c0-0.55,0.45-1,1-1h1.339 c0.55,0,1,0.45,1,1V28.099z"/>
+ </g>
+ <g>
+ <path d="M10.65,28.099c0,0.55-0.45,1-1,1.001H8.311c-0.55,0.001-1-0.449-1-0.999V26.76c0-0.55,0.45-1,1-1H9.65c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M15.411,28.099c0,0.55-0.45,1-1,1L13.072,29.1c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M20.173,28.099c0,0.55-0.45,1-1,1l-1.34,0.001c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M24.934,28.099c0,0.55-0.45,1-1,1l-1.34,0.001c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M29.695,28.099c0,0.55-0.45,1-1,1l-1.34,0.001c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M34.457,28.099c0,0.55-0.45,1-1,1L32.116,29.1c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1 V28.099z"/>
+ </g>
+ <g>
+ <path d="M39.218,28.099c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1V26.76c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V28.099z"/>
+ </g>
+ <g>
+ <path d="M43.979,28.099c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1V26.76c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V28.099z"/>
+ </g>
+ </g>
+ <g display="inline">
+ <g>
+ <path d="M5.889,32.161c0,0.55-0.45,1-1,1H3.549c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M10.65,32.161c0,0.55-0.45,1-1,1H8.311c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1H9.65c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M15.411,32.161c0,0.55-0.45,1-1,1h-1.339c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.339c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M20.173,32.161c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M24.934,32.161c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M29.695,32.161c0,0.55-0.45,1-1,1h-1.34c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.34c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M34.457,32.161c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M39.218,32.161c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ <g>
+ <path d="M43.979,32.161c0,0.55-0.45,1-1,1h-1.341c-0.55,0-1-0.45-1-1v-1.34c0-0.55,0.45-1,1-1h1.341c0.55,0,1,0.45,1,1V32.161z"/>
+ </g>
+ </g>
+</g></svg> \ No newline at end of file
diff --git a/shell/data/icons/module-language.svg b/shell/data/icons/module-language.svg
new file mode 100644
index 0000000..ce04cb4
--- /dev/null
+++ b/shell/data/icons/module-language.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-language">
+ <g display="inline">
+ <g>
+ <path clip-rule="evenodd" d="M35.805,13.962c-0.346-0.084-0.779-0.072-0.725-0.6 c0.24,0,0.482,0,0.725,0l-0.092,0.301L35.805,13.962z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M36.438,14.063l0.09-0.3c1.146-0.067,1.871,0.331,2.533,0.8 c3.684,0.596,9.051-0.669,10.676,2.2c-0.164,0.485-0.727,0.53-1.268,0.6c0.531,0.215,0.637,0.898,0.543,1.8 c-0.928-0.174-1.295-0.968-1.447-2c-0.553,0.389-1.396,0.457-2.352,0.4c-0.121,0.867,0.84,0.539,1.447,0.6 c0.057,0.472,0.629,0.373,0.543,1l-0.271,0.1l0.09,0.3c-0.549,0.658-0.812,1.635-0.723,3c-0.551,0.01-0.703-0.422-1.086-0.6 c0.26,1.426,0.908,1.89,0.723,3.4c-1.1-1.013-1.793,1.516-1.99,2.799c-0.627,0.161-0.693-0.297-1.266-0.199l-0.182-0.1l-0.18,0.1 c-0.475-1.659-2.096-3.383-3.076-1c0,0.4,0,0.8,0,1.199l-0.271-0.1l0.09,0.301c-1.533,0.073-0.889-3.936-3.438-3.4 c-0.357,1.338-1.098,2.254-2.535,2.4c-0.164,0.784,0.955,0.145,1.086,0.6c-0.146,1.638-1.449,1.998-1.99,3.2 c0.646,2.376-0.838,2.551-0.902,4.601c-0.834,0.479-0.881,1.828-1.811,2.2c-3.492-0.651-1.328-6.379-3.258-8.601 c-0.848-0.263-1.984-0.205-3.075-0.2c-2.032-1.712-0.716-5.163,0.724-6.8c-0.372-0.323-0.419-1.003-0.362-1.801 c0.481-0.002,1.034,0.076,1.267-0.2c-0.148-0.703-0.412-1.279-1.267-1.201c0.081-0.912,0.522-1.423,1.267-1.6 c0.269,0.237,0.282,0.755,0.543,1c0.512,0.165,0.469-0.282,0.904-0.201c0.191-0.877-0.611-0.657-0.543-1.4 c0.357-0.828,1.436-1.889,2.354-2c1.213-0.147,1.916,0.831,3.617,0.6c0.695-0.094,1.172-0.681,2.172-1 c0.594-0.19,1.852,0.085,2.354-0.601L36.438,14.063z M27.842,17.963c0.438-0.392,0.416-1-0.18-1.2 C27.766,17.115,27.441,17.938,27.842,17.963z M27.48,21.563c-0.186-0.944-2.604-0.928-2.353,0.4c0.483,0,0.966,0,1.448,0 l0.09,0.3l0.271-0.101c0,0.066,0,0.134,0,0.201c0.442,1.067,3.484,1.27,3.98,0c-1.439,0.273-2.379-0.674-3.256-0.4l0.09-0.301 L27.48,21.563z M32.365,26.764c0.031-0.501-0.277-0.626-0.541-0.8C31.791,26.464,32.102,26.59,32.365,26.764z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M48.018,21.863l0.09-0.3c0.316,0.184,0.4,0.625,0.361,1.2 c-0.547,0.261-1.043,0.579-1.627,0.8c-0.492-1.168,0.654-0.949,0.904-1.8L48.018,21.863z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M42.77,28.864l0.092-0.301c0.662,0.467,0.711,1.615,0.904,2.601 l-0.332-0.1l-0.211,0.3c-0.619-0.582-0.996-1.434-1.268-2.4c0.146,0.105,0.295,0.209,0.543,0.2c0-0.134,0-0.267,0-0.399 L42.77,28.864z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M11.376,25.163c0.423,0.067,0.78,0.206,0.905,0.601 l-0.271,0.233l0.09,0.367c-0.21-0.033-0.322,0.044-0.361,0.199c-0.465-0.02-0.291-0.744-0.543-1l0.271-0.1L11.376,25.163z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M46.299,27.764c-0.281-0.29-0.381-0.78-0.363-1.399 c0.182,0,0.363,0,0.545,0c0.104,0.418,0.447,0.57,0.361,1.199l-0.332-0.1L46.299,27.764z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M45.936,30.364c0.131,0.877-0.602,0.8-1.266,0.8 c-0.264-0.44-0.549-0.858-0.543-1.601c0.738-0.051,0.895-0.744,1.809-0.6c-0.057,0.465,0.029,0.768,0.182,1l-0.271,0.101 L45.936,30.364z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M46.389,30.265l-0.09-0.301c0.42-0.063,0.693,0.033,0.904,0.2 c-0.332,0.501-0.145,1.574-1.086,1.4c0-0.4,0-0.8,0-1.2L46.389,30.265z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M48.65,31.164c-0.553,0.146-0.531-0.345-1.086-0.199 c-0.086-0.716,1.123-1.144,1.268-0.4l-0.271,0.233L48.65,31.164z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M49.104,30.931l-0.092-0.366c0.926-0.487,1.51,0.948,2.715,0.8 c-0.617,0.261-0.084,0.855-0.361,1.199" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M49.918,32.765c0.291,0.117,1.43,2.391,1.447,3 c0.045,1.674-1.633,3.377-2.715,3.201c-0.922-0.152-0.688-0.955-1.447-1.601c-0.98,0.12-1.854,0.957-2.895,0.399 c-0.109-1.053,0.133-1.718,0.18-2.6c1.658-0.205,3.107-3.646,4.705-1.4C49.775,33.807,49.633,33.051,49.918,32.765z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M33.451,33.164c0.725,1.004,0.084,2.368-0.725,2.8 C32.002,34.962,32.742,33.707,33.451,33.164z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M48.65,39.165c0.383,0.062,0.039,0.948-0.361,0.8 C48.082,39.336,48.572,39.479,48.65,39.165z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M16.805,12.962c2.05,0,4.102,0,6.15,0 c0.007,0.195,0.223,0.155,0.363,0.2c0.324,0.701-0.65,1.677-1.084,2.2c-1.523,0.317-2.302,1.457-3.621,2 c-0.971-0.425-0.523-1.94-0.724-2.8c-0.439-0.464-2.139-0.687-2.532,0c1.822-0.026,1.732,2.399,0.18,2.6 c1.181-0.023,1.775,2.452,0.543,2.8l0.091-0.3l-0.272-0.1c-0.099-0.657-1.186,0.234-0.541,0.4l-0.092,0.3l0.271,0.101 c-2.093,0.085-2.461,2.079-3.98,2.799c0,0.201,0,0.4,0,0.601l-0.332-0.1l-0.21,0.3c-0.761-0.482-2.09-0.11-2.534,0.399 c0,0.534,0,1.067,0,1.601c0.622,0.076,1.287-0.828,1.628-0.4c-0.564,1.371,0.746,1.471,0.906,2.6l-0.272,0.201l0.272,0.199 c-0.433,0.062-1.751-0.617-2.534-1.199C7.746,26.816,7,25.966,6.673,25.163c-0.38-0.229-0.707,0.123-1.086-0.399 c-0.229-1.306-0.774-2.063-0.724-3.2c0.032-0.728,0.597-0.782,0.724-1.601c0.033-0.217-0.352-0.856-0.362-1.399 c-0.01-0.526,0.43-0.783,0-1.201c-1.454-0.274-1.845,0.627-3.076,0.6l0.09-0.199l-0.09-0.2c-0.231-0.521-0.397-0.604-0.182-1.2 c1.83-1.044,4.094-1.609,7.057-1.4c0.688-0.04,0.687-0.841,1.448-0.8c1.325-0.132,2.296,0.13,3.257,0.4 c0.705-0.021,0.311-1.256,0.904-1.4C15.303,13.035,16.436,13.422,16.805,12.962z M14.452,15.963 c0.286-0.02,0.628,0.027,0.542-0.4c-0.119,0-0.24,0-0.361,0C14.633,15.764,14.486,15.801,14.452,15.963z M11.92,17.763 c0.789-0.139,0.803,0.577,1.447,0.6c0.266-0.505,0.639-0.893,0.723-1.6C13.093,16.545,11.914,16.393,11.92,17.763z" fill="&fill_color;" fill-rule="evenodd"/>
+ <path clip-rule="evenodd" d="M11.467,28.364l-0.091-0.201 c1.866-1.496,4.541,0.503,5.247,2.201c0.822,0.426,2.057,0.393,2.352,1.4c-0.152,1.164-0.635,1.965-0.723,3.199 c-0.226,0.484-0.742,0.648-1.268,0.801c-0.201,2.777-2.827,3.017-2.17,6.201c0.453-0.035,0.566,0.307,0.723,0.6 c-0.36,0-0.723,0-1.085,0c-1.601-1.566-1.526-4.982-1.81-8.001c-1.498-1.305-2.468-3.841-1.267-6.001L11.467,28.364z" fill="&fill_color;" fill-rule="evenodd"/>
+ <g>
+
+ <path clip-rule="evenodd" d=" M48.018,21.863" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.1637"/>
+
+ <path clip-rule="evenodd" d=" M46.932,19.263" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.1637"/>
+
+ <path clip-rule="evenodd" d=" M43.434,31.064" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.8752"/>
+
+ <path clip-rule="evenodd" d=" M42.498,27.864" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.1506"/>
+
+ <path clip-rule="evenodd" d=" M38.971,28.063" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="1.2247"/>
+
+ <path clip-rule="evenodd" d=" M26.851,21.793" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.1448"/>
+
+ <path clip-rule="evenodd" d=" M12.01,25.997" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.8087"/>
+
+ <path clip-rule="evenodd" d=" M46.51,27.464" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="3.5214"/>
+
+ <path clip-rule="evenodd" d=" M46.752,28.264" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="3.5214"/>
+
+ <path clip-rule="evenodd" d=" M45.846,30.064" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.1602"/>
+
+ <path clip-rule="evenodd" d=" M49.104,30.931" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="3.1091"/>
+
+ <path clip-rule="evenodd" d=" M46.752,32.165" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.1381"/>
+
+ <path clip-rule="evenodd" d=" M15.266,20.263" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="1.6279"/>
+
+ <path clip-rule="evenodd" d=" M11.225,23.664" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.9155"/>
+
+ <path clip-rule="evenodd" d=" M11.467,28.364" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.0976"/>
+
+ <path clip-rule="evenodd" d=" M10.743,28.364" fill="&fill_color;" fill-rule="evenodd" stroke="#000000" stroke-linecap="round" stroke-width="2.0976"/>
+ </g>
+ </g>
+ </g>
+ <rect display="inline" fill="none" height="30.334" stroke="&fill_color;" stroke-width="3.5" width="50.67" x="2.25" y="12.625"/>
+</g></svg> \ No newline at end of file
diff --git a/shell/data/icons/module-modemconfiguration.svg b/shell/data/icons/module-modemconfiguration.svg
new file mode 100644
index 0000000..02ccc81
--- /dev/null
+++ b/shell/data/icons/module-modemconfiguration.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#ffffff">
+ <!ENTITY fill_color "none">
+]><svg enable-background="new 0 0 56.167 55" height="55px" version="1.1" viewBox="0 0 56.167 55" width="56.167px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="network-gsm">
+ <g>
+ <path d="M13.759,11.28 v28.937h0.002c0,0.004-0.002,0.008-0.002,0.014c0,7.05,5.715,12.763,12.764,12.763c7.047,0,12.762-5.713,12.762-12.763v-0.014 V11.28H13.759z" fill="&fill_color;" stroke="&stroke_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5"/>
+ <rect fill="&stroke_color;" height="9.702" width="14.063" x="19.43" y="16.902"/>
+
+ <line fill="&fill_color;" stroke="&stroke_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5" x1="39.286" x2="39.286" y1="11.28" y2="1.993"/>
+ </g>
+</g></svg>
diff --git a/shell/data/icons/module-network.svg b/shell/data/icons/module-network.svg
new file mode 100644
index 0000000..a750a38
--- /dev/null
+++ b/shell/data/icons/module-network.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-network">
+ <g display="inline">
+ <defs>
+ <path d="M14.897,34.339c0-10.144,8.224-18.367,18.367-18.367c3.929,0,7.562,1.244,10.549,3.345V0H0v43.812h17.55 C15.877,41.044,14.897,37.81,14.897,34.339z" id="SVGID_1_"/>
+ </defs>
+ <clipPath id="SVGID_2_">
+ <use overflow="visible" xlink:href="#SVGID_1_"/>
+ </clipPath>
+ <g clip-path="url(#SVGID_2_)">
+
+ <circle cx="21.47" cy="21.073" fill="none" r="18.368" stroke="&fill_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"/>
+
+ <circle cx="21.469" cy="21.073" fill="none" r="10.476" stroke="&fill_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"/>
+ <circle cx="21.469" cy="21.073" fill="&fill_color;" r="3.966"/>
+ </g>
+ </g>
+ <g display="inline">
+ <g>
+ <defs>
+ <rect height="18.367" id="SVGID_3_" width="36.736" x="14.897" y="34.339"/>
+ </defs>
+ <clipPath id="SVGID_4_">
+ <use overflow="visible" xlink:href="#SVGID_3_"/>
+ </clipPath>
+ <circle clip-path="url(#SVGID_4_)" cx="33.265" cy="34.339" fill="&fill_color;" r="18.368"/>
+ </g>
+ <circle cx="33.265" cy="34.339" fill="none" r="18.368" stroke="&fill_color;" stroke-width="3.5"/>
+ </g>
+</g></svg> \ No newline at end of file
diff --git a/shell/data/icons/module-power.svg b/shell/data/icons/module-power.svg
new file mode 100644
index 0000000..4db57ea
--- /dev/null
+++ b/shell/data/icons/module-power.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg enable-background="new 0 0 55 55" height="55px" id="Layer_1" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="module-energy">
+ <g display="inline" id="device-battery-charging-050">
+ <g>
+ <g>
+ <path d="M2.215,15.271v24.833l33.094,0.002V15.271H2.215z M20.817,26.089l-6.599,9.903l2.339-8.285h-2.472 l1.85-7.121h5.411l-2.773,5.503H20.817z" fill="&fill_color;"/>
+ </g>
+ </g>
+ <polygon fill="none" points="2.215,39.896 47.602,39.896 47.602,34.607 52.611,34.607 52.611,20.565 47.602,20.565 47.602,15.271 2.215,15.271 " stroke="&fill_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5"/>
+ </g>
+</g></svg> \ No newline at end of file
diff --git a/shell/data/icons/module-updater.svg b/shell/data/icons/module-updater.svg
new file mode 100644
index 0000000..a521f61
--- /dev/null
+++ b/shell/data/icons/module-updater.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#000">
+ <!ENTITY fill_color "#fff">
+]><svg height="55px" viewBox="0 0 55 55" width="55px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <g>
+ <g>
+ <path d="M 31.752 7.088 C 41.935 9.118 49.609 18.107 49.609 28.887 C 49.609 41.173 39.65 51.129 27.374 51.129 C 15.086 51.129 5.133 41.173 5.133 28.887 C 5.133 19.648 10.768 11.723 18.801 8.365 " fill="none" stroke="&fill_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5" />
+ <path d="M 36.134 15.154 L 31.752 7.088 L 40.439 4.13 " fill="none" stroke="&fill_color;" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.5" />
+ </g>
+ <g>
+ <g>
+ <path d="M 38.57 25.886 C 37.597 25.886 36.718 26.282 36.082 26.918 L 31.021 31.979 L 31.02 17.022 C 31.018 16.124 30.675 15.221 29.99 14.533 C 28.613 13.159 26.383 13.159 25.01 14.533 C 24.321 15.222 23.98 16.122 23.979 17.023 L 23.977 31.978 L 18.918 26.918 C 18.281 26.281 17.4 25.886 16.429 25.887 C 14.484 25.885 12.908 27.465 12.908 29.408 C 12.907 30.381 13.304 31.263 13.936 31.899 L 27.5 45.463 L 41.062 31.898 C 41.697 31.262 42.09 30.382 42.093 29.41 C 42.094 27.463 40.516 25.885 38.57 25.886 Z " fill="&fill_color;" stroke="none" />
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/shell/data/kbdconfig b/shell/data/kbdconfig
new file mode 100644
index 0000000..03c288a
--- /dev/null
+++ b/shell/data/kbdconfig
@@ -0,0 +1,3 @@
+# This is the sugar keyboard configuration for matchbox
+
+<Alt>return=fullscreen
diff --git a/shell/data/mime.defaults b/shell/data/mime.defaults
new file mode 100644
index 0000000..f07e22c
--- /dev/null
+++ b/shell/data/mime.defaults
@@ -0,0 +1,24 @@
+# MIME Activity service name
+
+application/pdf org.laptop.sugar.ReadActivity
+
+text/rtf org.laptop.AbiWordActivity
+text/plain org.laptop.AbiWordActivity
+application/x-abiword org.laptop.AbiWordActivity
+text/x-xml-abiword org.laptop.AbiWordActivity
+application/msword org.laptop.AbiWordActivity
+application/rtf org.laptop.AbiWordActivity
+
+image/png org.laptop.ImageViewerActivity
+image/gif org.laptop.ImageViewerActivity
+image/jpeg org.laptop.ImageViewerActivity
+text/html org.laptop.WebActivity
+application/xhtml+xml org.laptop.WebActivity
+application/xml org.laptop.WebActivity
+application/rss+xml org.laptop.WebActivity
+application/ogg org.laptop.sugar.Jukebox
+audio/ogg org.laptop.sugar.Jukebox
+video/ogg org.laptop.sugar.Jukebox
+
+text/x-python org.laptop.PippyActivity
+
diff --git a/shell/data/nm-user-settings.conf b/shell/data/nm-user-settings.conf
new file mode 100644
index 0000000..16e71e4
--- /dev/null
+++ b/shell/data/nm-user-settings.conf
@@ -0,0 +1,28 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="org.freedesktop.NetworkManagerUserSettings"/>
+
+ <allow send_destination="org.freedesktop.NetworkManagerUserSettings"/>
+ </policy>
+ <policy at_console="true">
+ <allow own="org.freedesktop.NetworkManagerUserSettings"/>
+
+ <allow send_destination="org.freedesktop.NetworkManagerUserSettings"/>
+
+ <!-- Only root can get secrets -->
+ <deny send_destination="org.freedesktop.NetworkManagerUserSettings"
+ send_interface="org.freedesktop.NetworkManagerSettings.Connection.Secrets"/>
+ </policy>
+ <policy context="default">
+ <deny send_destination="org.freedesktop.NetworkManagerUserSettings"/>
+
+ <allow send_destination="org.freedesktop.NetworkManagerUserSettings"
+ send_interface="org.freedesktop.DBus.Introspectable"/>
+ </policy>
+
+ <limit name="max_replies_per_connection">512</limit>
+</busconfig>
+
diff --git a/shell/data/sugar-emulator.desktop.in b/shell/data/sugar-emulator.desktop.in
new file mode 100644
index 0000000..6247bd7
--- /dev/null
+++ b/shell/data/sugar-emulator.desktop.in
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Sugar
+GenericName=Sugar Emulator
+Comment=The emulator for the Sugar Desktop Environment
+Exec=@prefix@/bin/sugar-emulator
+Terminal=false
+Type=Application
+Icon=sugar-xo
+Categories=Education;Teaching;
diff --git a/shell/data/sugar-xo.svg b/shell/data/sugar-xo.svg
new file mode 100644
index 0000000..b673179
--- /dev/null
+++ b/shell/data/sugar-xo.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#010101">
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="stock-xo_1_">
+ <path d="M33.233,35.1l10.102,10.1c0.752,0.75,1.217,1.783,1.217,2.932 c0,2.287-1.855,4.143-4.146,4.143c-1.145,0-2.178-0.463-2.932-1.211L27.372,40.961l-10.1,10.1c-0.75,0.75-1.787,1.211-2.934,1.211 c-2.284,0-4.143-1.854-4.143-4.141c0-1.146,0.465-2.184,1.212-2.934l10.104-10.102L11.409,24.995 c-0.747-0.748-1.212-1.785-1.212-2.93c0-2.289,1.854-4.146,4.146-4.146c1.143,0,2.18,0.465,2.93,1.214l10.099,10.102l10.102-10.103 c0.754-0.749,1.787-1.214,2.934-1.214c2.289,0,4.146,1.856,4.146,4.145c0,1.146-0.467,2.18-1.217,2.932L33.233,35.1z" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5"/>
+ <circle cx="27.371" cy="10.849" fill="&fill_color;" r="8.122" stroke="&stroke_color;" stroke-width="3.5"/>
+</g></svg> \ No newline at end of file
diff --git a/shell/data/sugar.desktop b/shell/data/sugar.desktop
new file mode 100644
index 0000000..2d7133f
--- /dev/null
+++ b/shell/data/sugar.desktop
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Sugar
+GenericName=Sugar
+Exec=sugar
+Type=Application
diff --git a/shell/data/sugar.schemas.in b/shell/data/sugar.schemas.in
new file mode 100644
index 0000000..2e6b820
--- /dev/null
+++ b/shell/data/sugar.schemas.in
@@ -0,0 +1,347 @@
+<?xml version="1.0"?>
+<gconfschemafile>
+ <schemalist>
+ <schema>
+ <key>/schemas/desktop/sugar/user/nick</key>
+ <applyto>/desktop/sugar/user/nick</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>User Name</short>
+ <long>User name that is used throughout the desktop.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/user/default_nick</key>
+ <applyto>/desktop/sugar/user/default_nick</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default>system</default>
+ <locale name="C">
+ <short>Default nick</short>
+ <long>"disabled" to ask nick on initialization; "system" to reuse UNIX account long name.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/user/color</key>
+ <applyto>/desktop/sugar/user/color</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>User Color</short>
+ <long>Color for the XO icon that is used throughout the
+ desktop. The string is composed of the stroke color and fill
+ color, format is that of rbg colors. Example: #AC32FF,#9A5200
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/sound/volume</key>
+ <applyto>/desktop/sugar/sound/volume</applyto>
+ <owner>sugar</owner>
+ <type>int</type>
+ <default>80</default>
+ <locale name="C">
+ <short>Volume Level</short>
+ <long>Volume level for the sound device.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/sound/mute</key>
+ <applyto>/desktop/sugar/sound/mute</applyto>
+ <owner>sugar</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Sound Muted</short>
+ <long>Setting for muting the sound device.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/backup_url</key>
+ <applyto>/desktop/sugar/backup_url</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>Backup URL</short>
+ <long>Url where the backup is saved to.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/date/timezone</key>
+ <applyto>/desktop/sugar/date/timezone</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default>UTC</default>
+ <locale name="C">
+ <short>Timezone</short>
+ <long>Timezone setting for the system.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/desktop/favorites_layout</key>
+ <applyto>/desktop/sugar/desktop/favorites_layout</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default>ring-layout</default>
+ <locale name="C">
+ <short>Favorites Layout</short>
+ <long>Layout of the favorites view.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/desktop/favorites_mode</key>
+ <applyto>/desktop/sugar/desktop/favorites_mode</applyto>
+ <owner>sugar</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Favorites resume mode</short>
+ <long>When in resume mode, clicking on a favorite icon will cause the last entry for that activity to be resumed.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/frame/edge_delay</key>
+ <applyto>/desktop/sugar/frame/edge_delay</applyto>
+ <owner>sugar</owner>
+ <type>int</type>
+ <default>1000</default>
+ <locale name="C">
+ <short>Edge Delay</short>
+ <long>Delay for the activation of the frame using the edges.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/frame/corner_delay</key>
+ <applyto>/desktop/sugar/frame/corner_delay</applyto>
+ <owner>sugar</owner>
+ <type>int</type>
+ <default>0</default>
+ <locale name="C">
+ <short>Corner Delay</short>
+ <long>Delay for the activation of the frame using the corners.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/collaboration/jabber_server</key>
+ <applyto>/desktop/sugar/collaboration/jabber_server</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default>jabber.sugarlabs.org</default>
+ <locale name="C">
+ <short>Jabber Server</short>
+ <long>Url of the jabber server to use.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/power/automatic</key>
+ <applyto>/desktop/sugar/power/automatic</applyto>
+ <owner>sugar</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Power Automatic</short>
+ <long>Power Automatic.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/power/extreme</key>
+ <applyto>/desktop/sugar/power/extreme</applyto>
+ <owner>sugar</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Power Extreme</short>
+ <long>Power Extreme. </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/collaboration/publish_gadget</key>
+ <applyto>/desktop/sugar/collaboration/publish_gadget</applyto>
+ <owner>sugar</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Publish to Gadget</short>
+ <long>If TRUE, Sugar will make us searchable for the other users of the Jabber server.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/show_logout</key>
+ <applyto>/desktop/sugar/show_logout</applyto>
+ <owner>sugar</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Show Log out</short>
+ <long>If TRUE, Sugar will show a "Log out" option.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/peripherals/keyboard/layouts</key>
+ <applyto>/desktop/sugar/peripherals/keyboard/layouts</applyto>
+ <owner>sugar</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <locale name="C">
+ <short>Keyboard layouts</short>
+ <long>List of keyboard layouts. Each entry should be in the form layout(variant)</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/peripherals/keyboard/options</key>
+ <applyto>/desktop/sugar/peripherals/keyboard/options</applyto>
+ <owner>sugar</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <locale name="C">
+ <short>Keyboard options</short>
+ <long>List of keyboard options.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/peripherals/keyboard/model</key>
+ <applyto>/desktop/sugar/peripherals/keyboard/model</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default>evdev</default>
+ <locale name="C">
+ <short>Keyboard model</short>
+ <long>The keyboard model to be used</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/font/default_face</key>
+ <applyto>/desktop/sugar/font/default_face</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default>Sans Serif</default>
+ <locale name="C">
+ <short>Default font face</short>
+ <long>Font face that is used throughout the desktop.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/font/default_size</key>
+ <applyto>/desktop/sugar/font/default_size</applyto>
+ <owner>sugar</owner>
+ <type>float</type>
+ <default>10</default>
+ <locale name="C">
+ <short>Default font size</short>
+ <long>Font size that is used throughout the desktop.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/i18n/langpackdir</key>
+ <applyto>/desktop/sugar/i18n/langpackdir</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>Directory to search for translations</short>
+ <long>Additional directories which can contain updated translations.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/network/gsm/username</key>
+ <applyto>/desktop/sugar/network/gsm/username</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>GSM network username</short>
+ <long>GSM network username configuration</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/network/gsm/password</key>
+ <applyto>/desktop/sugar/network/gsm/password</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>GSM network password</short>
+ <long>GSM network password configuration</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/network/gsm/number</key>
+ <applyto>/desktop/sugar/network/gsm/number</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default>*99#</default>
+ <locale name="C">
+ <short>GSM network number</short>
+ <long>GSM network telephone number configuration</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/network/gsm/apn</key>
+ <applyto>/desktop/sugar/network/gsm/apn</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>GSM network APN</short>
+ <long>GSM network access point name configuration</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/network/gsm/pin</key>
+ <applyto>/desktop/sugar/network/gsm/pin</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>GSM network PIN</short>
+ <long>GSM network personal identification number configuration</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/sugar/network/gsm/puk</key>
+ <applyto>/desktop/sugar/network/gsm/puk</applyto>
+ <owner>sugar</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>GSM network PUK</short>
+ <long>GSM network personal unlock key configuration</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/sugar/network/adhoc</key>
+ <applyto>/desktop/sugar/network/adhoc</applyto>
+ <owner>sugar</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Show Sugar Ad-hoc networks</short>
+ <long>If TRUE, Sugar will show default Ad-hoc networks for
+ channel 1,6 and 11. If Sugar sees no "known" network when
+ it starts, it does autoconnect to an Ad-hoc network.</long>
+ </locale>
+ </schema>
+
+ </schemalist>
+</gconfschemafile>
diff --git a/shell/data/sugar.xml.in b/shell/data/sugar.xml.in
new file mode 100644
index 0000000..6a7f253
--- /dev/null
+++ b/shell/data/sugar.xml.in
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/vnd.olpc-sugar">
+ <_comment>Sugar activity bundle</_comment>
+ <glob pattern="*.xo"/>
+ </mime-type>
+ <mime-type type="application/vnd.olpc-content">
+ <_comment>Sugar content bundle</_comment>
+ <glob pattern="*.xol"/>
+ </mime-type>
+</mime-info> \ No newline at end of file
diff --git a/shell/docs/GPL-C.txt b/shell/docs/GPL-C.txt
new file mode 100644
index 0000000..aa909b4
--- /dev/null
+++ b/shell/docs/GPL-C.txt
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
diff --git a/shell/docs/GPL-python.txt b/shell/docs/GPL-python.txt
new file mode 100644
index 0000000..96e81d1
--- /dev/null
+++ b/shell/docs/GPL-python.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
diff --git a/shell/docs/LGPL-C.txt b/shell/docs/LGPL-C.txt
new file mode 100644
index 0000000..88798f8
--- /dev/null
+++ b/shell/docs/LGPL-C.txt
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
diff --git a/shell/docs/LGPL-python.txt b/shell/docs/LGPL-python.txt
new file mode 100644
index 0000000..1db1ea4
--- /dev/null
+++ b/shell/docs/LGPL-python.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
diff --git a/shell/docs/controls.txt b/shell/docs/controls.txt
new file mode 100644
index 0000000..52591ea
--- /dev/null
+++ b/shell/docs/controls.txt
@@ -0,0 +1,199 @@
+Colors
+
+Black - palettes, popups
+Toolbar Grey #262626 - toolbars, expanded palette
+Button Grey #808080 - buttons
+Selection Grey #A6A6A6 - selection, expanded panels
+Panel Grey #C0C0C0 - panel, desktop
+Text field Grey #E5E5E5 - text field background
+White - pressed states and multiline text areas
+
+States
+
+Default - gtk.STATE_NORMAL
+Focused - gtk.STATE_SELECTED
+Pressed - gtk.STATE_ACTIVE
+Hover - gtk.STATE_PRELIGHT
+Inactive - gtk.STATE_INSENSITIVE
+
+gtk.Button
+
+* The image should work the same of the image button
+* Need to write a theme to match the visual style
+* Cancel should never be default because you can always activate it with Esc
+* Radius should be 1/2 of the control height
+* Write a list of stock icons people should use and replace them in the theme to match our visual style
+
+sugar.Icon
+
+* Used in canvas-like views so probably an Hippo item.
+* Svg Only.
+* It should support xo colors easily.
+* Rollovers with a focus mark.
+
+sugar.IconButton
+
+* Support for SVG and png.
+* Icons should be grey scale. But might be coloured with the XO colors (svg only)
+* Size of the button is 75 pixels, size of the icon canvas is 55 and suggested icon size is around 45.
+* States, defaults:
+ Hover : Black
+ Pressed : Rounded rectangle 61 pixels, 10 pixels of radius, filled in selection grey
+ Focused : Rounded rectangle 61 pixels, 10 pixels of radius, stroked in white 2.25 points
+ Inactive. Fallbacks if no inactive icon is specified.
+ Svg: Remove the fill and render the stroke in button grey
+ Png: just do some effect on the pixbuf, which also work for grey icons
+* You can set an icon for each states which replace the default except for the Hover state of buttons which has rollover.
+* "palette" boolean property. If true show an arrow active immediately on click (but also on hover)
+
+sugar.ToolButton (support for rollovers)
+
+* Contains IconButton
+* There is no palette but a tooltip.
+* Normal: Button grey rounded filled rectangle
+* Inactive: Button grey rounded stroked rectangle
+
+sugar.ToggleIconButton
+
+* Toggled should be like Pressed
+* Inconsistent should be the same of Default (the action depend on the cases)
+* Pressed state and Toggled state is Selection grey
+
+sugar.ToolIconButton
+
+* Contains a ToggleIconButton
+
+gtk.CheckButton
+
+* Match the visual design, shoul be possible with just theme changes
+
+gtk.RadioButton
+
+* Exactly like CheckButton just a different indicator
+
+gtk.OptionMenu
+
+* Match the visual style. Hopefully only theme changes.
+* Add the scroll thing.
+* Groups. Either by a normal separator or a titled separator.
+* Optional support for showing just the icon from the menu (maybe, low priority)
+* Allow fixed sizing of the "button" and ellipsize the label
+
+sugar.Entry
+
+* Support for packing icons before and after the entry. Extend gtk.Entry.
+* Activate/Cancel functionality.
+ Two buttons at the end to the entry and key bindings (Esc and Enter). They are visible only when there are changes.
+ The icons appear only when the field is focused and the content is changed since it gained focus.
+ When hitting escape revert and select all the text.
+
+gtk.ComboxBox
+
+* We miss accept/cancel functionality. Probably patch gtk to allow to replace the entry in the combo box with sugar.Entry.
+
+sugar.SearchEntry
+
+* Use sugar.Entry
+* Search button on the left. Clicking should focus the entry.
+* Cancel button (Esc) on the right, always visible when there is text in the entry. Clicking it will clear the text and focus the textfield.
+* Activate button (Enter) on the right displayed when the content of the text field changed from the last focus or activation.
+* While activating:
+ the Activate button becomes a Spinner.
+ clicking the close button also cancel the search.
+* When activation is completed:
+ The spinner goes away.
+ We *don't* clear the entry but we select the text.
+* Search can either be incremental or on activation. For incremental there is no Accept button. start_spinning and stop_spinning to control the spin icon. start would only spin for an amount of time decided by the widget itself (and documented).
+* The suggestions list is provided by the application. Need to figure out which api to use, either model or signal based.
+* Default implementation of suggestions which automatically save the latest searches.
+
+sugar.DateSelector
+sugar.DateComboBox (lower priority)
+
+* Pluggable calendar implementation to support different kind of calendars (localization).
+* Might reuse gtk.Calendar. We should unify month/year selectors and accellerate the movement gradually.
+
+gtk.SpinButton
+
+* Make it match the visual design, hopefully just theme changes
+
+sugar.ToolItem
+
+* Optional label, either text or icon
+* Used for example to have a label near a SpinButton. Clicking on the label should focus the spin button.
+
+gtk.ProgressBar
+
+* Make it match the visual design, hopefully just theme changes.
+* For determinate progress bars should we always pulse to show that there is activity (power consumption? necessary feedback?)
+* Do not use text inside the progress bar
+
+sugar.Spinner
+
+* pulse() call to keep it running with a timeout
+* stop()
+
+gtk.Range (or sugar.Slider?)
+
+* Property to show the fill in white color, probably default on.
+* Draw the discrete steps.
+* For colored sliders, subclass gtk.Range and add a gradient.
+
+sugar.LevelIndicator
+
+* Set the number of blocks
+* Set the level as percentage
+* Property for discrete or not
+* We can probably use a GtkAdjustment for most of the above.Rollovers
+
+
+gtk.TextView
+
+gtk.ScrolledWindow
+
+* Theme it to match the visual.
+
+sugar.ScrolledWindow
+
+* Support for markers. Line as default and optional support for other shapes (star for bookmarks, circles for xos...). Generic way of add marks and keep them updated (observer?)
+
+gtk.Expander
+
+gtk.Separator
+
+sugar.GroupBox
+
+* just a container
+* set_title and set_title_widget (checkbox, radiobutton...)
+* different color and separator under title
+
+gtk.TreeView
+
+gtk.Notebook
+
+* Expand to fill the whole space by default but property to turn it off
+* Switching tabs with the little arrows should page
+
+Palettes in ToolIconButton, IconButton
+* Inmediately on rollover, show the black background.
+* After a very short delay, show the primary state (name of the action and key shortcut).
+* After a bigger delay, show the popup secondary state.
+* Could be animated.
+* Menu Items would go on the top and then the free-form rollover content.
+* The popup would be a gtk.Window that contains a Label, a MenuShell, an hippo.Canvas (or whatever) and finally a button bar (OK/Cancel).
+* The popup will have a setPrimaryState(label, accelerator) method. For action buttons would be a MenuItem, for the others would only be a Label.
+* The primary state should already have the same width as the secondary state and the expandable areas.
+* Primary states appear and disappear automatically (with a short delay). A click outside makes it disappear instantly.
+* Secondary states appear after a delay, or with a single click on the icon.
+* Secondary disappears with the esc key, clicking outside the popup or clicking on a button inside.
+
+Toolbox
+* When an activity opens, the activity tab should be opened and the focus on the activity title.
+* We must provide an activity tab in the toolbox and would be good to also provide an standard Edit tab.
+
+Grab key
+* We probably will need the grab mode.
+* Highlight the scrollbar in the view the pointer is (the view that will scroll when moving the pointer).
+
+Clipboard
+* Window manager to handle in an invisible window in every corner and forward the events when they are not in the corner, or use XEvIE (X Event Interception Extension).
diff --git a/shell/docs/design.txt b/shell/docs/design.txt
new file mode 100644
index 0000000..37061af
--- /dev/null
+++ b/shell/docs/design.txt
@@ -0,0 +1,126 @@
+= Frame =
+
+== Activation and deactivation ==
+
+* Immediately access the frame by hitting any corner pixel (the exact corner point)
+* Hitting any of the screen edges activate the frame after 0.5s delay
+* Pressing and holding the frame key activate the frame until the key is released.
+* Pressing the frame key momentarily toggle the frame. To deactivate it another key press is necessary.
+
+= IRC logs =
+
+Frame
+
+eliason marcopg: First, you can immediately access the frame by hitting any corner pixel.
+dcbw marcopg: I think that's the issue, yes
+eliason Second, you can activate it from any edge, but there is a half second delay. In addition to the delay, the timer on the delay only ticks when the mouse is on an edge pixel and also below some threshold velocity, so if the mouse is moving it will not show up.
+eliason marcopg: Third, there will be a frame key. Pressing and holding this key will invoke the frame until the key is released. Pressing this key momentarily, however, will toggle the frame and keep it in view until the key is pressed again.
+eliason marcopg: All of these things are implemented in Flash (The frame key is 8, I think...), with the exception of the mouse velocity threshold on the edges.
+eliason marcopg: The only other minor usability issue I could see is adding a hit area in the corners. That is, once the frame is out, have an invisible triangle in each corner that is still considered part of the frame, so that rolling out of the frame to get from one edge to another doesn't hide the frame, by accident. In fact, doing this would make the delay on hide unnecessary.
+eliason marcopg: Oh, and other important edges case to think about on the frame: 1) When someone is dragginan object (XO, file, image, etc) the frame should come out prematurely and without delay (maybe once within a large grid cell of the edge) and highlight to indicate where the object could be dropped. 2) When the search field is active, the frame should remain out even if the mouse isn't over it. Only when the search is cleared should it hide again.
+eliason marcopg: The rollover states are as follows: 1) Immediate rollover is a black square in the frame cell itself. 2) Very shortly thereafter (about 1/4 sec) Is the Primary information label and 3) a bit longer after that (about 1/2 sec) the extended panel appears with additional info.
+
+Menu
+
+eliason marcopg: Deactivation is instantaneous at the moment, but again, based on testing with the software we may want to add a very short delay. Also, we may want again to have a invisible triangles between the grid cell in the frame and the extended panel.
+eliason Delay between mouse rollover and showing black square: 0
+eliason Delay before primary info animation begins: 1/10 sec
+eliason Duration of primary info extension animation: 1/5 sec
+eliason Delay from end of primary info animation until secondary info: 1/2 sec
+Duration of secondary info animation: 1/5 sec
+
+Text layout
+
+eliason marcopg: Well, first of all, in the latest screens which we haven't sent out yet, the primary info rollover is designed to fit the text to the nearest microgrid, regardless of the size of the secondary info panel. The second animation segment will both extend the width and height to fit.
+eliason marcopg: As far as cutoff goes, I think that's a reasonable solution. We should allow the primary info text to be as long as the secondary info panel, and beyond that an ellipsis would be a good way to go, though hopefully designers are strongly encouraged NOT to let that happen.
+eliason marcopg: However, there may be cases when we don't want that to happen. I can think of one, which you haven't seen yet: "Invite with X X X X X." The new activity/invite rollover might have the XOs who you are implicitly inviting to start an activity with listed, and we couldn't cut that off (Though we CANget around it and list, say, a max of three people and then indicate that there are 5 more not shown, etc.)
+eliason marcopg: Right. I think that, in most cases, there should be some template for it. If the designer is creating a GUI for an application and making toolsets (such as the color chooser), then we know how big all of those are. Things like "just text" will mostly show up in OS applications like the clippings and such, so we can just pick a preferred size that shows enough text to be meaningful without compromising too much of the screen.
+
+Mesh view
+
+eliason marcopg: also important regarding the results: the fill color should be the background color, so they look like outlines, and the line color should be near enough to the background to make them less contrasty. Also, all XOs in the result set should be z-sorted to the front of their groups. That's key.
+eliason marcopg: The activity icons and XOs are treated separately, so it may be the case that several XOs in a group match the search but the activity their in doesn't, and they would be grayed out independently.
+eliason marcopg: yes, only the color change. Colored stuff is the result. We don't want to actually make things disappear.
+
+
+Mesh discussion
+
+eliason marcopg: Well, the terminology we're now using for the zoom level labels is: My Activities, My Friends, My Neighbors.
+eliason marcopg: Alright, true, so the working terminology (not the labels for the search field, but still used by all of us) is: home, friends, mesh
+eliason marcopg: If you treat each frieeliason marcopg: If you treat each friend or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly.nd or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly.
+eliason marcopg: If you treat each friend or group as a node in a graph, and each edge in the graph as a spring, you can let the system reach an equilibrium using a basic physics simulation that will spread the nodes out evenly.
+eliason marcopg: There's lots of info on this type of thing online. To do it right within a given box, you also have to add anchored springs at the corners and such to stretch the whole thing out to fill the space.
+eliason OK, so another basic idea is to keep a very rough downsampled grayscale image around....
+eliason The grayscale value would map to the number of XOs within the grid cell on screen.
+eliason marcopg: Then, when placing a new one you could just find the best place to place it , though now that I think about it that would probably require a simulated annealing algorithm or something else clever to do...
+marcopg eliason, do you mean macro cell here?
+marcopg i.e. every buddy would be placed in one macro cell
+eliason marcopg: Well, actually I guess you'd kind of want a blurred brayscale image, where each object placed represents a white circle, but with a gaussian blur so that it acts like a topographic map of the mesh.
+eliason marcopg: The white spots would be dense, like hills, the black spots would be void of people, like holes. Then to place a new one, you kind of roll a simulated marble around until you find a good hole to place it in...
+eliason marcopg: And, yet another idea, which could be used in conjunction with or independent of the above. You could simply place a small repulsive force between the objects, so that they push each other apart slightly. You could just place at random and have them adjust accordingly. This works very much like the spring model, though.
+eliason Of course, the drawback of the third idea is that it's n^2 in the number of groups on the mesh, but that number should never be that large.
+eliason The spring model is a little more complicated, but you only have to place springs between nearby objects, which reduces that somewhat.
+eliason marcopg: But actually, I think #3 might be the easiest to implement, and work just as well. It works nicely since it could still allow you to drag them around and the rest of the mesh would react naturally. In the spring model, you'd have to dynamically add and break spring connections when a node is moved around.
+marcopg eliason, mm was just thinking about this would interact with custom placed nodes...
+marcopg eliason, I never done something similar before so I will really need to play a bit with it...
+eliason marcopg: Also, #3 is more forgiving: In the spring model, placing one new node will move EVERY node in the mesh somewhat, if even just a small amount, since the whole system adjusts. With the repulsion force, only nearby nodes would be affected, except of course through a chain reaction...
+eliason marcopg: I'm sure we can find documentation. Basically, you calculate the distance between the two nodes (pythag) and if that distance is less than some threshold you compute the angle between them (atan2) and then you give each one a small repulsive acceleration, and update each frame by treating each with its own acceleration, velocity, and position.
+eliason marcopg: radiusConstant + (numXos*radiusScale) + ((index%3)*offsetScale) <-- that gets pretty close to what I'm working with now.
+eliason marcopg: One addition: When the groups are small, we don't want to add the snowflake effect, since they fit in neat geometric shapes around the ring. So we get....actually, here's the ugly line of code: radius = 25 + .3*(Math.max(participants.length-10,0)) + (i%3)*.5*(Math.max(participants.length-10,0));
+eliason marcopg: The added ugliness is a bit of code that zeros out the 2nd two quantities if there are less than 10 people in the group. You could just place them in an if block actually, but I'd done it this way in case I wanted to change the thresholds independently...eliason marcopg: The added ugliness is a bit of code that zeros out the 2nd two quantities if there are less than 10 people in the group. You could just place them in an if block actually, but I'd done it this way in case I wanted to change the thresholds independently...
+eliason marcopg: OK, cool. The animation is a simple easing algorithm: position += (targetPostition - position)*percentage.
+eliason marcopg: Well, that's a function of the radius and the angle computed from above. targetX = radius*cos(angle), targetY = radius*sin(angle), for each XO.
+marcopg eliason, aaah I see now
+
+eliason marcopg: The basic problem is that people are crossing an index that is a multiple of the mod, so everyone shifts in and out. What if, instead, we adjusted the indeces of every XO with an index of modValue*c greater than the XO that left, and subtract modValue from each of their indices?
+eliason With mod 3, we basically have 3 levels of the ring. This solution would just shift ONE of those rings couter-clockwise one XO position, leaving the other two rings intact as is. We move many fewer XOs than before, but we minimize the movement any given XO has to make by spreading it across the ring level instead of moving the last XO all the way across the circle...eliason marcopg: The basic problem is that people are crossing an index that is a multiple of the mod, so everyone shifts in and out. What if, instead, we adjusted the indeces of every XO with an index of modValue*c greater than the XO that left, and subtract modValue from each of their indices?
+eliason With mod 3, we basically have 3 levels of the ring. This solution would just shift ONE of those rings couter-clockwise one XO position, leaving the other two rings intact as is. We move many fewer XOs than before, but we minimize the movement any given XO has to make by spreading it across the ring level instead of moving the last XO all the way across the circle...
+eliason marcopg: The final detail of that, beyond shifting each index down by the mod value, is to shift the very last group of people in the ring down to fill all the holes, if you get my meaning...
+
+Activity startup feedback
+
+I agree we certainly need feedback for this sort of thing. For
+starters, the icon of the selected activity should immediately appear
+in the ring. Perhaps we can apply some small animation to this
+activity icon to indicate that it is starting up. Marco, could you
+use HSV for the icon color, and modulate the S(aturation) on a sin
+curve so the color pulses betwen, say, 0 and 192 until the activity
+starts, at which point it slides up to 255?
+
+Clipboard
+
+<marcopg> eliason, when should the frame be automatically showed? when
+starting the drag or when hitting the corner
+<marcopg> eliason, (the first one would be tricky to implement)
+<eliason> marcopg: Initially we wanted it to happen on drag, but after
+thinking about this more, it's a bad idea, since it would hide the toolbars,
+and some activities may have toolbars that support drag and drop also. As
+such, we probably just keep the hot corners as is, and perhaps implement the
+"warm edges" too, but only when dragging...
+<marcopg> eliason, which reminds me... the plan is to completely drop edges at
+this point? or at least give it a try? (for the not dragging case)
+<eliason> I still think it's worth trying, but I think the general consensus
+was that we should drop it. That's also the easier option, so for now, I
+guess it's fine.
+<marcopg> ok
+<marcopg> eliason, what should be the title of the clipboard rollover? (we are
+trying to get text objects right for now, but if you have general ideas...)
+<eliason> marcopg: Well, it would depend on what is in the clipboard. For
+instance, if I copy some text, it should say "text clipping", or if I copy an
+image it should say "picture clipping"
+<marcopg> eliason, so [name of the object] + clipping?
+<eliason> marcopg: If it is an activity object, it should be the name of the
+object i.e. "Eben's Shark Drawing", etc.
+<marcopg> oh ok
+<eliason> It's only a clipping if it is part of another larger context.
+<eliason> If the whole thing is an object itself, we use the object's name.
+<marcopg> eliason, I see now
+<marcopg> eliason, we want a preview of the objectm right? For text, should we
+show part of the text in the rollover?
+<eliason> marcopg: yeah, probably the first n characters of it, with an
+ellipsis at the end.
+<marcopg> eliason, on multiple lines I guess?
+<marcopg> something like, 4 lines of text on a 2 grid cells large menu, and
+ellipsize after that
+<marcopg> (the exact numbers doesn't matter, just the logic
+<eliason> marcopg: Right.
diff --git a/shell/docs/release_howto.txt b/shell/docs/release_howto.txt
new file mode 100644
index 0000000..db877e0
--- /dev/null
+++ b/shell/docs/release_howto.txt
@@ -0,0 +1,73 @@
+''' This is the release process of the sugar tarballs sugar(shell),
+sugar-toolkit and sugar-base described in a pytish way and
+instructions for sugar packagers
+'''
+
+# Release sugar tarballs
+
+for package in [sugar, sugar-toolkit, sugar-base, sugar-artwork]:
+ # Release a new version in git
+ Pull the latest sources.
+ Increase the version number in configure.ac
+ # this will create you a tarball and does a check if it builds fine
+ # e.g. it will check if all the files containing translations are
+ # in po/POTFILES.in
+ make distcheck
+
+ if that succeed:
+ # commit the change, log it as "Release [version_number]" (e.g. 0.79.1)
+ git commit -a
+ # Tag the release:
+ git tag v[version_number]
+ # Then push both the tag and the change:
+ git push --tags
+ git push
+ else:
+ break
+
+ # Upload the package
+ Upload the tarball to
+ shell.sugarlabs.org:/pub/sugarlabs/sources/sucrose/glucose/$name/$name-$version
+
+ # Verify the upload of the package
+ Check that the package has been uploaded fine: \
+ http://download.sugarlabs.org/sources/sucrose/glucose/$name/$name-$version
+
+# Package sugar for Fedora
+# - For announcements of the Sucrose release subscribe at the sugar-devel
+# mailing list; you can filter for the [ANNOUNCE] tag
+# - Uploaded tarballs can be found at:
+# glucose: http://download.sugarlabs.org/sources/sucrose/glucose/$name/$name-$version
+# fructose: http://download.sugarlabs.org/sources/sucrose/fructose/$name/$name-$version
+# more about the taxonomy: http://sugarlabs.org/go/Taxonomy
+
+# more info on fedora packaging:
+# http://fedoraproject.org/wiki/PackageMaintainers/UpdatingPackageHowTo
+# request permissions to contribute to the fedora package:
+# https://admin.fedoraproject.org/pkgdb/packages/name/[package]
+
+if not cvs_package:
+ # Get sugar from fedora cvs:
+ CVSROOT=:ext:erikos@cvs.fedoraproject.org:/cvs/pkgs cvs co [package]
+ cd cvs_package
+else:
+ cd cvs_package
+ cvs update
+
+cd current release
+make new-sources FILES="[tarball-created-with-make_distcheck]"
+
+# Change the version in the spec
+Bump the release number
+Edit the Changelog
+# verify your changes
+cvs diff -u
+make srpm
+
+make clog
+cvs commit -F clog
+
+make tag
+make build
+
+# Do the same for the other branches e.g. devel
diff --git a/shell/extensions/Makefile.am b/shell/extensions/Makefile.am
new file mode 100644
index 0000000..d4ab534
--- /dev/null
+++ b/shell/extensions/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = cpsection deviceicon globalkey
diff --git a/shell/extensions/cpsection/Makefile.am b/shell/extensions/cpsection/Makefile.am
new file mode 100644
index 0000000..a92b5dd
--- /dev/null
+++ b/shell/extensions/cpsection/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = aboutme aboutcomputer datetime frame keyboard language \
+ modemconfiguration network power updater
+
+sugardir = $(pkgdatadir)/extensions/cpsection
+sugar_PYTHON = __init__.py
diff --git a/shell/extensions/cpsection/__init__.py b/shell/extensions/cpsection/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shell/extensions/cpsection/__init__.py
diff --git a/shell/extensions/cpsection/aboutcomputer/Makefile.am b/shell/extensions/cpsection/aboutcomputer/Makefile.am
new file mode 100644
index 0000000..a3bdec8
--- /dev/null
+++ b/shell/extensions/cpsection/aboutcomputer/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/aboutcomputer
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/aboutcomputer/__init__.py b/shell/extensions/cpsection/aboutcomputer/__init__.py
new file mode 100644
index 0000000..ceb515a
--- /dev/null
+++ b/shell/extensions/cpsection/aboutcomputer/__init__.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+CLASS = 'AboutComputer'
+ICON = 'module-about_my_computer'
+TITLE = _('About my Computer')
+
diff --git a/shell/extensions/cpsection/aboutcomputer/model.py b/shell/extensions/cpsection/aboutcomputer/model.py
new file mode 100644
index 0000000..898d79c
--- /dev/null
+++ b/shell/extensions/cpsection/aboutcomputer/model.py
@@ -0,0 +1,138 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import os
+import logging
+import re
+import subprocess
+from gettext import gettext as _
+import errno
+
+from jarabe import config
+
+_logger = logging.getLogger('ControlPanel - AboutComputer')
+_not_available = _('Not available')
+
+def get_aboutcomputer():
+ msg = 'Serial Number: %s \nBuild Number: %s \nFirmware Number: %s \n' \
+ % (get_serial_number(), get_build_number(), get_firmware_number())
+ return msg
+
+def print_aboutcomputer():
+ print get_aboutcomputer()
+
+def get_serial_number():
+ serial_no = _read_file('/ofw/serial-number')
+ if serial_no is None:
+ serial_no = _not_available
+ return serial_no
+
+def print_serial_number():
+ serial_no = get_serial_number()
+ if serial_no is None:
+ serial_no = _not_available
+ print serial_no
+
+def get_build_number():
+ build_no = _read_file('/boot/olpc_build')
+
+ if build_no is None:
+ build_no = _read_file('/etc/redhat-release')
+
+ if build_no is None:
+ try:
+ popen = subprocess.Popen(['lsb_release', '-ds'],
+ stdout=subprocess.PIPE)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ else:
+ build_no, stderr_ = popen.communicate()
+
+ if build_no is None or not build_no:
+ build_no = _not_available
+
+ return build_no
+
+def print_build_number():
+ print get_build_number()
+
+def get_firmware_number():
+ firmware_no = _read_file('/ofw/openprom/model')
+ if firmware_no is None:
+ firmware_no = _not_available
+ else:
+ firmware_no = re.split(" +", firmware_no)
+ if len(firmware_no) == 3:
+ firmware_no = firmware_no[1]
+ return firmware_no
+
+def print_firmware_number():
+ print get_firmware_number()
+
+def get_wireless_firmware():
+ try:
+ info = subprocess.Popen(["/usr/sbin/ethtool", "-i", "eth0"],
+ stdout=subprocess.PIPE).stdout.readlines()
+ except OSError:
+ return _not_available
+ try:
+ wireless_firmware = [line for line in info
+ if line.startswith('firmware')][0].split()[1]
+ except IndexError:
+ wireless_firmware = _not_available
+ return wireless_firmware
+
+def print_wireless_firmware():
+ print get_wireless_firmware()
+
+def _read_file(path):
+ if os.access(path, os.R_OK) == 0:
+ return None
+
+ fd = open(path, 'r')
+ value = fd.read()
+ fd.close()
+ if value:
+ value = value.strip('\n')
+ return value
+ else:
+ _logger.debug('No information in file or directory: %s', path)
+ return None
+
+def get_license():
+ license_file = os.path.join(config.data_path, 'GPLv2')
+ lang = os.environ['LANG']
+ if lang.endswith("UTF-8"):
+ lang = lang[:-6]
+
+ try_file = license_file + "." + lang
+ if os.path.isfile(try_file):
+ license_file = try_file
+ else:
+ try_file = license_file + "." + lang.split("_")[0]
+ if os.path.isfile(try_file):
+ license_file = try_file
+
+ try:
+ fd = open(license_file)
+ # remove 0x0c page breaks which can't be rendered in text views
+ license_text = fd.read().replace('\x0c', '')
+ fd.close()
+ except IOError:
+ license_text = _not_available
+ return license_text
diff --git a/shell/extensions/cpsection/aboutcomputer/view.py b/shell/extensions/cpsection/aboutcomputer/view.py
new file mode 100644
index 0000000..b6ff43f
--- /dev/null
+++ b/shell/extensions/cpsection/aboutcomputer/view.py
@@ -0,0 +1,217 @@
+# coding=utf-8
+# Copyright (C) 2008, OLPC
+# Copyright (C) 2009 Simon Schampijer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+from gettext import gettext as _
+
+import gtk
+
+from sugar.graphics import style
+
+from jarabe import config
+from jarabe.controlpanel.sectionview import SectionView
+
+class AboutComputer(SectionView):
+ def __init__(self, model, alerts=None):
+ SectionView.__init__(self)
+
+ self._model = model
+
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+ self.set_spacing(style.DEFAULT_SPACING)
+
+ self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+ scrollwindow = gtk.ScrolledWindow()
+ scrollwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.pack_start(scrollwindow, expand=True)
+ scrollwindow.show()
+
+ self._vbox = gtk.VBox()
+ scrollwindow.add_with_viewport(self._vbox)
+ self._vbox.show()
+
+ if os.path.exists('/ofw'):
+ self._setup_identity()
+
+ self._setup_software()
+ self._setup_copyright()
+
+ def _setup_identity(self):
+ separator_identity = gtk.HSeparator()
+ self._vbox.pack_start(separator_identity, expand=False)
+ separator_identity.show()
+
+ label_identity = gtk.Label(_('Identity'))
+ label_identity.set_alignment(0, 0)
+ self._vbox.pack_start(label_identity, expand=False)
+ label_identity.show()
+ vbox_identity = gtk.VBox()
+ vbox_identity.set_border_width(style.DEFAULT_SPACING * 2)
+ vbox_identity.set_spacing(style.DEFAULT_SPACING)
+
+ box_identity = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_serial = gtk.Label(_('Serial Number:'))
+ label_serial.set_alignment(1, 0)
+ label_serial.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ box_identity.pack_start(label_serial, expand=False)
+ self._group.add_widget(label_serial)
+ label_serial.show()
+ label_serial_no = gtk.Label(self._model.get_serial_number())
+ label_serial_no.set_alignment(0, 0)
+ box_identity.pack_start(label_serial_no, expand=False)
+ label_serial_no.show()
+ vbox_identity.pack_start(box_identity, expand=False)
+ box_identity.show()
+
+ self._vbox.pack_start(vbox_identity, expand=False)
+ vbox_identity.show()
+
+ def _setup_software(self):
+ separator_software = gtk.HSeparator()
+ self._vbox.pack_start(separator_software, expand=False)
+ separator_software.show()
+
+ label_software = gtk.Label(_('Software'))
+ label_software.set_alignment(0, 0)
+ self._vbox.pack_start(label_software, expand=False)
+ label_software.show()
+ box_software = gtk.VBox()
+ box_software.set_border_width(style.DEFAULT_SPACING * 2)
+ box_software.set_spacing(style.DEFAULT_SPACING)
+
+ box_build = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_build = gtk.Label(_('Build:'))
+ label_build.set_alignment(1, 0)
+ label_build.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ box_build.pack_start(label_build, expand=False)
+ self._group.add_widget(label_build)
+ label_build.show()
+ label_build_no = gtk.Label(self._model.get_build_number())
+ label_build_no.set_alignment(0, 0)
+ box_build.pack_start(label_build_no, expand=False)
+ label_build_no.show()
+ box_software.pack_start(box_build, expand=False)
+ box_build.show()
+
+ box_sugar = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_sugar = gtk.Label(_('Sugar:'))
+ label_sugar.set_alignment(1, 0)
+ label_sugar.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ box_sugar.pack_start(label_sugar, expand=False)
+ self._group.add_widget(label_sugar)
+ label_sugar.show()
+ label_sugar_ver = gtk.Label(config.version)
+ label_sugar_ver.set_alignment(0, 0)
+ box_sugar.pack_start(label_sugar_ver, expand=False)
+ label_sugar_ver.show()
+ box_software.pack_start(box_sugar, expand=False)
+ box_sugar.show()
+
+ if os.path.exists('/ofw'):
+ box_firmware = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_firmware = gtk.Label(_('Firmware:'))
+ label_firmware.set_alignment(1, 0)
+ label_firmware.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ box_firmware.pack_start(label_firmware, expand=False)
+ self._group.add_widget(label_firmware)
+ label_firmware.show()
+ label_firmware_no = gtk.Label(self._model.get_firmware_number())
+ label_firmware_no.set_alignment(0, 0)
+ box_firmware.pack_start(label_firmware_no, expand=False)
+ label_firmware_no.show()
+ box_software.pack_start(box_firmware, expand=False)
+ box_firmware.show()
+
+ box_wireless_fw = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_wireless_fw = gtk.Label(_('Wireless Firmware:'))
+ label_wireless_fw.set_alignment(1, 0)
+ label_wireless_fw.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ box_wireless_fw.pack_start(label_wireless_fw, expand=False)
+ self._group.add_widget(label_wireless_fw)
+ label_wireless_fw.show()
+ wireless_fw_no = self._model.get_wireless_firmware()
+ label_wireless_fw_no = gtk.Label(wireless_fw_no)
+ label_wireless_fw_no.set_alignment(0, 0)
+ box_wireless_fw.pack_start(label_wireless_fw_no, expand=False)
+ label_wireless_fw_no.show()
+ box_software.pack_start(box_wireless_fw, expand=False)
+ box_wireless_fw.show()
+
+ self._vbox.pack_start(box_software, expand=False)
+ box_software.show()
+
+ def _setup_copyright(self):
+ separator_copyright = gtk.HSeparator()
+ self._vbox.pack_start(separator_copyright, expand=False)
+ separator_copyright.show()
+
+ label_copyright = gtk.Label(_('Copyright and License'))
+ label_copyright.set_alignment(0, 0)
+ self._vbox.pack_start(label_copyright, expand=False)
+ label_copyright.show()
+ vbox_copyright = gtk.VBox()
+ vbox_copyright.set_border_width(style.DEFAULT_SPACING * 2)
+ vbox_copyright.set_spacing(style.DEFAULT_SPACING)
+
+ label_copyright = gtk.Label("© 2006-2010 One Laptop per Child "
+ "Association Inc, Sugar Labs Inc, "
+ "Red Hat Inc, Collabora Ltd "
+ "and Contributors.")
+ label_copyright.set_alignment(0, 0)
+ label_copyright.set_size_request(gtk.gdk.screen_width() / 2, -1)
+ label_copyright.set_line_wrap(True)
+ label_copyright.show()
+ vbox_copyright.pack_start(label_copyright, expand=False)
+
+ label_info = gtk.Label(_("Sugar is the graphical user interface that "
+ "you are looking at. Sugar is free software, "
+ "covered by the GNU General Public License, "
+ "and you are welcome to change it and/or "
+ "distribute copies of it under certain "
+ "conditions described therein."))
+ label_info.set_alignment(0, 0)
+ label_info.set_line_wrap(True)
+ label_info.set_size_request(gtk.gdk.screen_width() / 2, -1)
+ label_info.show()
+ vbox_copyright.pack_start(label_info, expand=False)
+
+ expander = gtk.Expander(_("Full license:"))
+ expander.connect("notify::expanded", self.license_expander_cb)
+ expander.show()
+ vbox_copyright.pack_start(expander, expand=True)
+
+ self._vbox.pack_start(vbox_copyright, expand=True)
+ vbox_copyright.show()
+
+ def license_expander_cb(self, expander, param_spec):
+ # load/destroy the license viewer on-demand, to avoid storing the
+ # GPL in memory at all times
+ if expander.get_expanded():
+ view_license = gtk.TextView()
+ view_license.set_editable(False)
+ view_license.get_buffer().set_text(self._model.get_license())
+ view_license.show()
+ expander.add(view_license)
+ else:
+ expander.get_child().destroy()
diff --git a/shell/extensions/cpsection/aboutme/Makefile.am b/shell/extensions/cpsection/aboutme/Makefile.am
new file mode 100644
index 0000000..9ca91d2
--- /dev/null
+++ b/shell/extensions/cpsection/aboutme/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/aboutme
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/aboutme/__init__.py b/shell/extensions/cpsection/aboutme/__init__.py
new file mode 100644
index 0000000..98843e1
--- /dev/null
+++ b/shell/extensions/cpsection/aboutme/__init__.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import gconf
+
+from sugar.graphics.xocolor import XoColor
+
+CLASS = 'AboutMe'
+ICON = 'module-about_me'
+TITLE = _('About Me')
+client = gconf.client_get_default()
+COLOR = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+
diff --git a/shell/extensions/cpsection/aboutme/model.py b/shell/extensions/cpsection/aboutme/model.py
new file mode 100644
index 0000000..8500799
--- /dev/null
+++ b/shell/extensions/cpsection/aboutme/model.py
@@ -0,0 +1,115 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from gettext import gettext as _
+import gconf
+
+_COLORS = {'red': {'dark':'#b20008', 'medium':'#e6000a', 'light':'#ffadce'},
+ 'orange': {'dark':'#9a5200', 'medium':'#c97e00', 'light':'#ffc169'},
+ 'yellow': {'dark':'#807500', 'medium':'#be9e00', 'light':'#fffa00'},
+ 'green': {'dark':'#008009', 'medium':'#00b20d', 'light':'#8bff7a'},
+ 'blue': {'dark':'#00588c', 'medium':'#005fe4', 'light':'#bccdff'},
+ 'purple': {'dark':'#5e008c', 'medium':'#7f00bf', 'light':'#d1a3ff'}
+ }
+
+_MODIFIERS = ('dark', 'medium', 'light')
+
+def get_nick():
+ client = gconf.client_get_default()
+ return client.get_string("/desktop/sugar/user/nick")
+
+def print_nick():
+ print get_nick()
+
+def set_nick(nick):
+ """Set the nickname.
+ nick : e.g. 'walter'
+ """
+ if not nick:
+ raise ValueError(_("You must enter a name."))
+ if not isinstance(nick, unicode):
+ nick = unicode(nick, 'utf-8')
+ client = gconf.client_get_default()
+ client.set_string("/desktop/sugar/user/nick", nick)
+ return 1
+
+def get_color():
+ client = gconf.client_get_default()
+ return client.get_string("/desktop/sugar/user/color")
+
+def print_color():
+ color_string = get_color()
+ tmp = color_string.split(',')
+
+ stroke_tuple = None
+ fill_tuple = None
+ for color in _COLORS:
+ for hue in _COLORS[color]:
+ if _COLORS[color][hue] == tmp[0]:
+ stroke_tuple = (color, hue)
+ if _COLORS[color][hue] == tmp[1]:
+ fill_tuple = (color, hue)
+
+ if stroke_tuple is not None:
+ print _('stroke: color=%s hue=%s') % (stroke_tuple[0],
+ stroke_tuple[1])
+ else:
+ print _('stroke: %s') % (tmp[0])
+ if fill_tuple is not None:
+ print _('fill: color=%s hue=%s') % (fill_tuple[0], fill_tuple[1])
+ else:
+ print _('fill: %s') % (tmp[1])
+
+def set_color(stroke, fill, stroke_modifier='medium', fill_modifier='medium'):
+ """Set the system color by setting a fill and stroke color.
+ fill : [red, orange, yellow, blue, green, purple]
+ stroke : [red, orange, yellow, blue, green, purple]
+ hue stroke : [dark, medium, light] (optional)
+ hue fill : [dark, medium, light] (optional)
+ """
+
+ if stroke_modifier not in _MODIFIERS or fill_modifier not in _MODIFIERS:
+ print (_("Error in specified color modifiers."))
+ return
+ if stroke not in _COLORS or fill not in _COLORS:
+ print (_("Error in specified colors."))
+ return
+
+ if stroke_modifier == fill_modifier:
+ if fill_modifier == 'medium':
+ fill_modifier = 'light'
+ else:
+ fill_modifier = 'medium'
+
+ color = _COLORS[stroke][stroke_modifier] + ',' \
+ + _COLORS[fill][fill_modifier]
+
+ client = gconf.client_get_default()
+ client.set_string("/desktop/sugar/user/color", color)
+ return 1
+
+def get_color_xo():
+ client = gconf.client_get_default()
+ return client.get_string("/desktop/sugar/user/color")
+
+def set_color_xo(color):
+ """Set a color with an XoColor
+ This method is used by the graphical user interface
+ """
+ client = gconf.client_get_default()
+ client.set_string("/desktop/sugar/user/color", color)
+ return 1
diff --git a/shell/extensions/cpsection/aboutme/view.py b/shell/extensions/cpsection/aboutme/view.py
new file mode 100644
index 0000000..95314a1
--- /dev/null
+++ b/shell/extensions/cpsection/aboutme/view.py
@@ -0,0 +1,340 @@
+# Copyright (C) 2008, OLPC
+# Copyright (C) 2010, Sugar Labs
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gobject
+from gettext import gettext as _
+
+from sugar.graphics.icon import Icon
+from sugar.graphics import style
+from sugar.graphics.xocolor import XoColor, colors
+
+from jarabe.controlpanel.sectionview import SectionView
+from jarabe.controlpanel.inlinealert import InlineAlert
+
+_STROKE_COLOR = 0
+_FILL_COLOR = 1
+
+
+def _get_next_stroke_color(color):
+ """ Return the next color pair in the list that shares the same fill
+ as color. """
+ current_index = _get_current_index(color)
+ if current_index == -1:
+ return "%s,%s" % (color.stroke, color.fill)
+ next_index = _next_index(current_index)
+ while(colors[next_index][_FILL_COLOR] != \
+ colors[current_index][_FILL_COLOR]):
+ next_index = _next_index(next_index)
+ return "%s,%s" % (colors[next_index][_STROKE_COLOR],
+ colors[next_index][_FILL_COLOR])
+
+
+def _get_previous_stroke_color(color):
+ """ Return the previous color pair in the list that shares the same fill
+ as color. """
+ current_index = _get_current_index(color)
+ if current_index == -1:
+ return "%s,%s" % (color.stroke, color.fill)
+ previous_index = _previous_index(current_index)
+ while (colors[previous_index][_FILL_COLOR] != \
+ colors[current_index][_FILL_COLOR]):
+ previous_index = _previous_index(previous_index)
+ return "%s,%s" % (colors[previous_index][_STROKE_COLOR],
+ colors[previous_index][_FILL_COLOR])
+
+
+def _get_next_fill_color(color):
+ """ Return the next color pair in the list that shares the same stroke
+ as color. """
+ current_index = _get_current_index(color)
+ if current_index == -1:
+ return "%s,%s" % (color.stroke, color.fill)
+ next_index = _next_index(current_index)
+ while (colors[next_index][_STROKE_COLOR] != \
+ colors[current_index][_STROKE_COLOR]):
+ next_index = _next_index(next_index)
+ return "%s,%s" % (colors[next_index][_STROKE_COLOR],
+ colors[next_index][_FILL_COLOR])
+
+
+def _get_previous_fill_color(color):
+ """ Return the previous color pair in the list that shares the same stroke
+ as color. """
+ current_index = _get_current_index(color)
+ if current_index == -1:
+ return "%s,%s" % (color.stroke, color.fill)
+ previous_index = _previous_index(current_index)
+ while (colors[previous_index][_STROKE_COLOR] != \
+ colors[current_index][_STROKE_COLOR]):
+ previous_index = _previous_index(previous_index)
+ return "%s,%s" % (colors[previous_index][_STROKE_COLOR],
+ colors[previous_index][_FILL_COLOR])
+
+
+def _next_index(current_index):
+ next_index = current_index + 1
+ if next_index == len(colors):
+ next_index = 0
+ return next_index
+
+
+def _previous_index(current_index):
+ previous_index = current_index - 1
+ if previous_index < 0:
+ previous_index = len(colors)-1
+ return previous_index
+
+
+def _get_current_index(color):
+ return colors.index([color.stroke, color.fill])
+
+
+_PREVIOUS_FILL_COLOR = 0
+_NEXT_FILL_COLOR = 1
+_CURRENT_COLOR = 2
+_NEXT_STROKE_COLOR = 3
+_PREVIOUS_STROKE_COLOR = 4
+
+
+class EventIcon(gtk.EventBox):
+ __gtype_name__ = "SugarEventIcon"
+
+ def __init__(self, **kwargs):
+ gtk.EventBox.__init__(self)
+
+ self.icon = Icon(pixel_size=style.XLARGE_ICON_SIZE, **kwargs)
+
+ self.set_visible_window(False)
+ self.set_app_paintable(True)
+ self.set_events(gtk.gdk.BUTTON_PRESS_MASK)
+
+ self.add(self.icon)
+ self.icon.show()
+
+
+class ColorPicker(EventIcon):
+ __gsignals__ = {
+ 'color-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([object]))
+ }
+
+ def __init__(self, picker):
+ EventIcon.__init__(self)
+
+ self.icon.props.icon_name = 'computer-xo'
+ self._picker = picker
+ self._color = None
+
+ self.icon.props.pixel_size = style.XLARGE_ICON_SIZE
+
+ self.connect('button_press_event', self.__pressed_cb, picker)
+
+ def update(self, color):
+ if self._picker == _PREVIOUS_FILL_COLOR:
+ self._color = XoColor(_get_previous_fill_color(color))
+ elif self._picker == _PREVIOUS_STROKE_COLOR:
+ self._color = XoColor(_get_previous_stroke_color(color))
+ elif self._picker == _NEXT_FILL_COLOR:
+ self._color = XoColor(_get_next_fill_color(color))
+ elif self._picker == _NEXT_STROKE_COLOR:
+ self._color = XoColor(_get_next_stroke_color(color))
+ else:
+ self._color = color
+ self.icon.props.xo_color = self._color
+
+ def __pressed_cb(self, button, event, picker):
+ if picker != _CURRENT_COLOR:
+ self.emit('color-changed', self._color)
+
+
+class AboutMe(SectionView):
+
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = model
+ self.restart_alerts = alerts
+ self._nick_sid = 0
+ self._color_valid = True
+ self._nick_valid = True
+
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+ self.set_spacing(style.DEFAULT_SPACING)
+ self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+ self._color_label = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._color_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._color_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._color_alert = None
+
+ self._pickers = {
+ _PREVIOUS_FILL_COLOR: ColorPicker(_PREVIOUS_FILL_COLOR),
+ _NEXT_FILL_COLOR: ColorPicker(_NEXT_FILL_COLOR),
+ _CURRENT_COLOR: ColorPicker(_CURRENT_COLOR),
+ _NEXT_STROKE_COLOR: ColorPicker(_NEXT_STROKE_COLOR),
+ _PREVIOUS_STROKE_COLOR: ColorPicker(_PREVIOUS_STROKE_COLOR)
+ }
+
+ self._setup_color()
+ initial_color = XoColor(self._model.get_color_xo())
+ self._update_pickers(initial_color)
+
+ self._nick_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._nick_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._nick_entry = None
+ self._nick_alert = None
+ self._setup_nick()
+ self.setup()
+
+ def _setup_nick(self):
+ self._nick_entry = gtk.Entry()
+ self._nick_entry.modify_bg(gtk.STATE_INSENSITIVE,
+ style.COLOR_WHITE.get_gdk_color())
+ self._nick_entry.modify_base(gtk.STATE_INSENSITIVE,
+ style.COLOR_WHITE.get_gdk_color())
+ self._nick_entry.set_width_chars(25)
+ self._nick_box.pack_start(self._nick_entry, expand=False)
+ self._nick_entry.show()
+
+ label_entry_error = gtk.Label()
+ self._group.add_widget(label_entry_error)
+ self._nick_alert_box.pack_start(label_entry_error, expand=False)
+ label_entry_error.show()
+
+ self._nick_alert = InlineAlert()
+ self._nick_alert_box.pack_start(self._nick_alert)
+ if 'nick' in self.restart_alerts:
+ self._nick_alert.props.msg = self.restart_msg
+ self._nick_alert.show()
+
+ self._center_in_panel = gtk.Alignment(0.5)
+ self._center_in_panel.add(self._nick_box)
+ self.pack_start(self._center_in_panel, False)
+ self.pack_start(self._nick_alert_box, False)
+ self._nick_box.show()
+ self._nick_alert_box.show()
+ self._center_in_panel.show()
+
+ def _setup_color(self):
+ label_color = gtk.Label(_('Click to change your color:'))
+ label_color.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ self._group.add_widget(label_color)
+ self._color_label.pack_start(label_color, expand=False)
+ label_color.show()
+
+ for picker_index in sorted(self._pickers.keys()):
+ if picker_index == _CURRENT_COLOR:
+ left_separator = gtk.SeparatorToolItem()
+ left_separator.show()
+ self._color_box.pack_start(left_separator, expand=False)
+
+ picker = self._pickers[picker_index]
+ picker.show()
+ self._color_box.pack_start(picker, expand=False)
+
+ if picker_index == _CURRENT_COLOR:
+ right_separator = gtk.SeparatorToolItem()
+ right_separator.show()
+ self._color_box.pack_start(right_separator, expand=False)
+
+ label_color_error = gtk.Label()
+ self._group.add_widget(label_color_error)
+ self._color_alert_box.pack_start(label_color_error, expand=False)
+ label_color_error.show()
+
+ self._color_alert = InlineAlert()
+ self._color_alert_box.pack_start(self._color_alert)
+ if 'color' in self.restart_alerts:
+ self._color_alert.props.msg = self.restart_msg
+ self._color_alert.show()
+
+ self._center_in_panel = gtk.Alignment(0.5)
+ self._center_in_panel.add(self._color_box)
+ self.pack_start(self._color_label, False)
+ self.pack_start(self._center_in_panel, False)
+ self.pack_start(self._color_alert_box, False)
+ self._color_label.show()
+ self._color_box.show()
+ self._color_alert_box.show()
+ self._center_in_panel.show()
+
+ def setup(self):
+ self._nick_entry.set_text(self._model.get_nick())
+ self._color_valid = True
+ self._nick_valid = True
+ self.needs_restart = False
+
+ self._nick_entry.connect('changed', self.__nick_changed_cb)
+ for picker in self._pickers.values():
+ picker.connect('color-changed', self.__color_changed_cb)
+
+ def undo(self):
+ self._model.undo()
+ self._nick_alert.hide()
+ self._color_alert.hide()
+
+ def _update_pickers(self, color):
+ for picker in self._pickers.values():
+ picker.update(color)
+
+ def _validate(self):
+ if self._nick_valid and self._color_valid:
+ self.props.is_valid = True
+ else:
+ self.props.is_valid = False
+
+ def __nick_changed_cb(self, widget, data=None):
+ if self._nick_sid:
+ gobject.source_remove(self._nick_sid)
+ self._nick_sid = gobject.timeout_add(self._APPLY_TIMEOUT,
+ self.__nick_timeout_cb, widget)
+
+ def __nick_timeout_cb(self, widget):
+ self._nick_sid = 0
+
+ if widget.get_text() == self._model.get_nick():
+ return False
+ try:
+ self._model.set_nick(widget.get_text())
+ except ValueError, detail:
+ self._nick_alert.props.msg = detail
+ self._nick_valid = False
+ else:
+ self._nick_alert.props.msg = self.restart_msg
+ self._nick_valid = True
+ self.needs_restart = True
+ self.restart_alerts.append('nick')
+ self._validate()
+ self._nick_alert.show()
+ return False
+
+ def __color_changed_cb(self, colorpicker, color):
+ self._model.set_color_xo(color.to_string())
+ self.needs_restart = True
+ self._color_alert.props.msg = self.restart_msg
+ self._color_valid = True
+ self.restart_alerts.append('color')
+
+ self._validate()
+ self._color_alert.show()
+
+ self._update_pickers(color)
+
+ return False
diff --git a/shell/extensions/cpsection/datetime/Makefile.am b/shell/extensions/cpsection/datetime/Makefile.am
new file mode 100644
index 0000000..b5b518e
--- /dev/null
+++ b/shell/extensions/cpsection/datetime/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/datetime
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/datetime/__init__.py b/shell/extensions/cpsection/datetime/__init__.py
new file mode 100644
index 0000000..fc9be45
--- /dev/null
+++ b/shell/extensions/cpsection/datetime/__init__.py
@@ -0,0 +1,21 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+CLASS = 'TimeZone'
+ICON = 'module-date_and_time'
+TITLE = _('Date & Time')
diff --git a/shell/extensions/cpsection/datetime/model.py b/shell/extensions/cpsection/datetime/model.py
new file mode 100644
index 0000000..76064e4
--- /dev/null
+++ b/shell/extensions/cpsection/datetime/model.py
@@ -0,0 +1,92 @@
+# Copyright (C) 2007, 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+#
+# The timezone config is based on the system-config-date
+# (http://fedoraproject.org/wiki/SystemConfig/date) tool.
+# Parts of the code were reused.
+#
+
+import os
+from gettext import gettext as _
+import gconf
+
+_zone_tab = '/usr/share/zoneinfo/zone.tab'
+
+def _initialize():
+ '''Initialize the docstring of the set function'''
+ if set_timezone.__doc__ is None:
+ # when running under 'python -OO', all __doc__ fields are None,
+ # so += would fail -- and this function would be unnecessary anyway.
+ return
+ timezones = read_all_timezones()
+ for timezone in timezones:
+ set_timezone.__doc__ += timezone + '\n'
+
+def read_all_timezones(fn=_zone_tab):
+ fd = open (fn, 'r')
+ lines = fd.readlines()
+ fd.close()
+ timezones = []
+ for line in lines:
+ if line.startswith('#'):
+ continue
+ line = line.split()
+ if len(line) > 1:
+ timezones.append(line[2])
+ timezones.sort()
+
+ for offset in xrange(-12, 13):
+ if offset < 0:
+ tz = 'GMT%d' % offset
+ elif offset > 0:
+ tz = 'GMT+%d' % offset
+ else:
+ tz = 'GMT'
+ timezones.append(tz)
+ for offset in xrange(-12, 13):
+ if offset < 0:
+ tz = 'UTC%d' % offset
+ elif offset > 0:
+ tz = 'UTC+%d' % offset
+ else:
+ tz = 'UTC'
+ timezones.append(tz)
+ return timezones
+
+def get_timezone():
+ client = gconf.client_get_default()
+ return client.get_string('/desktop/sugar/date/timezone')
+
+def print_timezone():
+ print get_timezone()
+
+def set_timezone(timezone):
+ """Set the system timezone
+ timezone : e.g. 'America/Los_Angeles'
+ """
+ timezones = read_all_timezones()
+ if timezone in timezones:
+ os.environ['TZ'] = timezone
+ client = gconf.client_get_default()
+ client.set_string('/desktop/sugar/date/timezone', timezone)
+ else:
+ raise ValueError(_("Error timezone does not exist."))
+ return 1
+
+# inilialize the docstrings for the timezone
+_initialize()
+
diff --git a/shell/extensions/cpsection/datetime/view.py b/shell/extensions/cpsection/datetime/view.py
new file mode 100644
index 0000000..58719b4
--- /dev/null
+++ b/shell/extensions/cpsection/datetime/view.py
@@ -0,0 +1,138 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gobject
+from gettext import gettext as _
+
+from sugar.graphics import style
+from sugar.graphics import iconentry
+
+from jarabe.controlpanel.sectionview import SectionView
+from jarabe.controlpanel.inlinealert import InlineAlert
+
+class TimeZone(SectionView):
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = model
+ self.restart_alerts = alerts
+ self._zone_sid = 0
+ self._cursor_change_handler = None
+
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+ self.set_spacing(style.DEFAULT_SPACING)
+
+ self.connect("realize", self.__realize_cb)
+
+ self._entry = iconentry.IconEntry()
+ self._entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY,
+ 'system-search')
+ self._entry.add_clear_button()
+ self._entry.modify_bg(gtk.STATE_INSENSITIVE,
+ style.COLOR_WHITE.get_gdk_color())
+ self._entry.modify_base(gtk.STATE_INSENSITIVE,
+ style.COLOR_WHITE.get_gdk_color())
+ self.pack_start(self._entry, False)
+ self._entry.show()
+
+ self._scrolled_window = gtk.ScrolledWindow()
+ self._scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self._scrolled_window.set_shadow_type(gtk.SHADOW_IN)
+
+ self._store = gtk.ListStore(gobject.TYPE_STRING)
+ zones = model.read_all_timezones()
+ for zone in zones:
+ self._store.append([zone])
+
+ self._treeview = gtk.TreeView(self._store)
+ self._treeview.set_search_entry(self._entry)
+ self._treeview.set_search_equal_func(self._search)
+ self._treeview.set_search_column(0)
+ self._scrolled_window.add(self._treeview)
+ self._treeview.show()
+
+ self._timezone_column = gtk.TreeViewColumn(_('Timezone'))
+ self._cell = gtk.CellRendererText()
+ self._timezone_column.pack_start(self._cell, True)
+ self._timezone_column.add_attribute(self._cell, 'text', 0)
+ self._timezone_column.set_sort_column_id(0)
+ self._treeview.append_column(self._timezone_column)
+
+ self.pack_start(self._scrolled_window)
+ self._scrolled_window.show()
+
+ self._zone_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self.pack_start(self._zone_alert_box, False)
+
+ self._zone_alert = InlineAlert()
+ self._zone_alert_box.pack_start(self._zone_alert)
+ if 'zone' in self.restart_alerts:
+ self._zone_alert.props.msg = self.restart_msg
+ self._zone_alert.show()
+ self._zone_alert_box.show()
+
+ self.setup()
+
+ def setup(self):
+ zone = self._model.get_timezone()
+ for row in self._store:
+ if zone == row[0]:
+ self._treeview.set_cursor(row.path, self._timezone_column,
+ False)
+ self._treeview.scroll_to_cell(row.path, self._timezone_column,
+ True, 0.5, 0.5)
+ break
+
+ self.needs_restart = False
+ self._cursor_change_handler = self._treeview.connect( \
+ "cursor-changed", self.__zone_changed_cd)
+
+ def undo(self):
+ self._treeview.disconnect(self._cursor_change_handler)
+ self._model.undo()
+ self._zone_alert.hide()
+
+ def __realize_cb(self, widget):
+ self._entry.grab_focus()
+
+ def _search(self, model, column, key, iterator, data=None):
+ value = model.get_value(iterator, column)
+ if key.lower() in value.lower():
+ return False
+ return True
+
+ def __zone_changed_cd(self, treeview, data=None):
+ list_, row = treeview.get_selection().get_selected()
+ if not row:
+ return False
+ if self._model.get_timezone() == self._store.get_value(row, 0):
+ return False
+
+ if self._zone_sid:
+ gobject.source_remove(self._zone_sid)
+ self._zone_sid = gobject.timeout_add(self._APPLY_TIMEOUT,
+ self.__zone_timeout_cb, row)
+ return True
+
+ def __zone_timeout_cb(self, row):
+ self._zone_sid = 0
+ self._model.set_timezone(self._store.get_value(row, 0))
+ self.restart_alerts.append('zone')
+ self.needs_restart = True
+ self._zone_alert.props.msg = self.restart_msg
+ self._zone_alert.show()
+ return False
diff --git a/shell/extensions/cpsection/frame/Makefile.am b/shell/extensions/cpsection/frame/Makefile.am
new file mode 100644
index 0000000..1e09c04
--- /dev/null
+++ b/shell/extensions/cpsection/frame/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/frame
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/frame/__init__.py b/shell/extensions/cpsection/frame/__init__.py
new file mode 100644
index 0000000..a93f9c7
--- /dev/null
+++ b/shell/extensions/cpsection/frame/__init__.py
@@ -0,0 +1,21 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+CLASS = 'Frame'
+ICON = 'module-frame'
+TITLE = _('Frame')
diff --git a/shell/extensions/cpsection/frame/model.py b/shell/extensions/cpsection/frame/model.py
new file mode 100644
index 0000000..9eea9ad
--- /dev/null
+++ b/shell/extensions/cpsection/frame/model.py
@@ -0,0 +1,63 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from gettext import gettext as _
+import gconf
+
+def get_corner_delay():
+ client = gconf.client_get_default()
+ corner_delay = client.get_int('/desktop/sugar/frame/corner_delay')
+ return corner_delay
+
+def print_corner_delay():
+ print get_corner_delay()
+
+def set_corner_delay(delay):
+ """Set a delay for the activation of the frame using hot corners.
+ instantaneous: 0 (0 milliseconds)
+ delay: 100 (100 milliseconds)
+ never: 1000 (disable activation)
+ """
+ try:
+ int(delay)
+ except ValueError:
+ raise ValueError(_("Value must be an integer."))
+ client = gconf.client_get_default()
+ client.set_int('/desktop/sugar/frame/corner_delay', int(delay))
+ return 0
+
+def get_edge_delay():
+ client = gconf.client_get_default()
+ edge_delay = client.get_int('/desktop/sugar/frame/edge_delay')
+ return edge_delay
+
+def print_edge_delay():
+ print get_edge_delay()
+
+def set_edge_delay(delay):
+ """Set a delay for the activation of the frame using warm edges.
+ instantaneous: 0 (0 milliseconds)
+ delay: 100 (100 milliseconds)
+ never: 1000 (disable activation)
+ """
+ try:
+ int(delay)
+ except ValueError:
+ raise ValueError(_("Value must be an integer."))
+ client = gconf.client_get_default()
+ client.set_int('/desktop/sugar/frame/edge_delay', int(delay))
+ return 0
diff --git a/shell/extensions/cpsection/frame/view.py b/shell/extensions/cpsection/frame/view.py
new file mode 100644
index 0000000..cbe43bb
--- /dev/null
+++ b/shell/extensions/cpsection/frame/view.py
@@ -0,0 +1,232 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gobject
+from gettext import gettext as _
+
+from sugar.graphics import style
+
+from jarabe.controlpanel.sectionview import SectionView
+from jarabe.controlpanel.inlinealert import InlineAlert
+
+_never = _('never')
+_instantaneous = _('instantaneous')
+_seconds_label = _('%s seconds')
+_MAX_DELAY = 1000
+
+class Frame(SectionView):
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = model
+ self._corner_delay_sid = 0
+ self._corner_delay_is_valid = True
+ self._corner_delay_change_handler = None
+ self._edge_delay_sid = 0
+ self._edge_delay_is_valid = True
+ self._edge_delay_change_handler = None
+ self.restart_alerts = alerts
+
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+ self.set_spacing(style.DEFAULT_SPACING)
+ self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+ separator = gtk.HSeparator()
+ self.pack_start(separator, expand=False)
+ separator.show()
+
+ label_activation = gtk.Label(_('Activation Delay'))
+ label_activation.set_alignment(0, 0)
+ self.pack_start(label_activation, expand=False)
+ label_activation.show()
+
+ self._box_sliders = gtk.VBox()
+ self._box_sliders.set_border_width(style.DEFAULT_SPACING * 2)
+ self._box_sliders.set_spacing(style.DEFAULT_SPACING)
+
+ self._corner_delay_slider = None
+ self._corner_delay_alert = None
+ self._setup_corner()
+
+ self._edge_delay_slider = None
+ self._edge_delay_alert = None
+ self._setup_edge()
+
+ self.pack_start(self._box_sliders, expand=False)
+ self._box_sliders.show()
+
+ self.setup()
+
+ def _setup_corner(self):
+ box_delay = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_delay = gtk.Label(_('Corner'))
+ label_delay.set_alignment(1, 0.75)
+ label_delay.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ box_delay.pack_start(label_delay, expand=False)
+ self._group.add_widget(label_delay)
+ label_delay.show()
+
+ adj = gtk.Adjustment(value=100, lower=0, upper=_MAX_DELAY,
+ step_incr=100, page_incr=100, page_size=0)
+ self._corner_delay_slider = gtk.HScale(adj)
+ self._corner_delay_slider.set_digits(0)
+ self._corner_delay_slider.connect('format-value',
+ self.__corner_delay_format_cb)
+ box_delay.pack_start(self._corner_delay_slider)
+ self._corner_delay_slider.show()
+ self._box_sliders.pack_start(box_delay, expand=False)
+ box_delay.show()
+
+ self._corner_delay_alert = InlineAlert()
+ label_delay_error = gtk.Label()
+ self._group.add_widget(label_delay_error)
+
+ delay_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ delay_alert_box.pack_start(label_delay_error, expand=False)
+ label_delay_error.show()
+ delay_alert_box.pack_start(self._corner_delay_alert, expand=False)
+ self._box_sliders.pack_start(delay_alert_box, expand=False)
+ delay_alert_box.show()
+ if 'corner_delay' in self.restart_alerts:
+ self._corner_delay_alert.props.msg = self.restart_msg
+ self._corner_delay_alert.show()
+
+ def _setup_edge(self):
+ box_delay = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_delay = gtk.Label(_('Edge'))
+ label_delay.set_alignment(1, 0.75)
+ label_delay.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ box_delay.pack_start(label_delay, expand=False)
+ self._group.add_widget(label_delay)
+ label_delay.show()
+
+ adj = gtk.Adjustment(value=100, lower=0, upper=_MAX_DELAY,
+ step_incr=100, page_incr=100, page_size=0)
+ self._edge_delay_slider = gtk.HScale(adj)
+ self._edge_delay_slider.set_digits(0)
+ self._edge_delay_slider.connect('format-value',
+ self.__edge_delay_format_cb)
+ box_delay.pack_start(self._edge_delay_slider)
+ self._edge_delay_slider.show()
+ self._box_sliders.pack_start(box_delay, expand=False)
+ box_delay.show()
+
+ self._edge_delay_alert = InlineAlert()
+ label_delay_error = gtk.Label()
+ self._group.add_widget(label_delay_error)
+
+ delay_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ delay_alert_box.pack_start(label_delay_error, expand=False)
+ label_delay_error.show()
+ delay_alert_box.pack_start(self._edge_delay_alert, expand=False)
+ self._box_sliders.pack_start(delay_alert_box, expand=False)
+ delay_alert_box.show()
+ if 'edge_delay' in self.restart_alerts:
+ self._edge_delay_alert.props.msg = self.restart_msg
+ self._edge_delay_alert.show()
+
+ def setup(self):
+ self._corner_delay_slider.set_value(self._model.get_corner_delay())
+ self._edge_delay_slider.set_value(self._model.get_edge_delay())
+ self._corner_delay_is_valid = True
+ self._edge_delay_is_valid = True
+ self.needs_restart = False
+ self._corner_delay_change_handler = self._corner_delay_slider.connect( \
+ 'value-changed', self.__corner_delay_changed_cb)
+ self._edge_delay_change_handler = self._edge_delay_slider.connect( \
+ 'value-changed', self.__edge_delay_changed_cb)
+
+ def undo(self):
+ self._corner_delay_slider.disconnect(self._corner_delay_change_handler)
+ self._edge_delay_slider.disconnect(self._edge_delay_change_handler)
+ self._model.undo()
+ self._corner_delay_alert.hide()
+ self._edge_delay_alert.hide()
+
+ def _validate(self):
+ if self._edge_delay_is_valid and self._corner_delay_is_valid:
+ self.props.is_valid = True
+ else:
+ self.props.is_valid = False
+
+ def __corner_delay_changed_cb(self, scale, data=None):
+ if self._corner_delay_sid:
+ gobject.source_remove(self._corner_delay_sid)
+ self._corner_delay_sid = gobject.timeout_add( \
+ self._APPLY_TIMEOUT, self.__corner_delay_timeout_cb, scale)
+
+ def __corner_delay_timeout_cb(self, scale):
+ self._corner_delay_sid = 0
+ if scale.get_value() == self._model.get_corner_delay():
+ return
+ try:
+ self._model.set_corner_delay(scale.get_value())
+ except ValueError, detail:
+ self._corner_delay_alert.props.msg = detail
+ self._corner_delay_is_valid = False
+ else:
+ self._corner_delay_alert.props.msg = self.restart_msg
+ self._corner_delay_is_valid = True
+ self.needs_restart = True
+ self.restart_alerts.append('corner_delay')
+
+ self._validate()
+ self._corner_delay_alert.show()
+ return False
+
+ def __corner_delay_format_cb(self, scale, value):
+ if value == _MAX_DELAY:
+ return _never
+ elif value == 0:
+ return _instantaneous
+ else:
+ return _seconds_label % (value / _MAX_DELAY)
+
+ def __edge_delay_changed_cb(self, scale, data=None):
+ if self._edge_delay_sid:
+ gobject.source_remove(self._edge_delay_sid)
+ self._edge_delay_sid = gobject.timeout_add( \
+ self._APPLY_TIMEOUT, self.__edge_delay_timeout_cb, scale)
+
+ def __edge_delay_timeout_cb(self, scale):
+ self._edge_delay_sid = 0
+ if scale.get_value() == self._model.get_edge_delay():
+ return
+ try:
+ self._model.set_edge_delay(scale.get_value())
+ except ValueError, detail:
+ self._edge_delay_alert.props.msg = detail
+ self._edge_delay_is_valid = False
+ else:
+ self._edge_delay_alert.props.msg = self.restart_msg
+ self._edge_delay_is_valid = True
+ self.needs_restart = True
+ self.restart_alerts.append('edge_delay')
+
+ self._validate()
+ self._edge_delay_alert.show()
+ return False
+
+ def __edge_delay_format_cb(self, scale, value):
+ if value == _MAX_DELAY:
+ return _never
+ elif value == 0:
+ return _instantaneous
+ else:
+ return _seconds_label % (value / _MAX_DELAY)
diff --git a/shell/extensions/cpsection/keyboard/Makefile.am b/shell/extensions/cpsection/keyboard/Makefile.am
new file mode 100644
index 0000000..7a95da5
--- /dev/null
+++ b/shell/extensions/cpsection/keyboard/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/keyboard
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/keyboard/__init__.py b/shell/extensions/cpsection/keyboard/__init__.py
new file mode 100644
index 0000000..568e7a5
--- /dev/null
+++ b/shell/extensions/cpsection/keyboard/__init__.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2009, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+CLASS = 'Keyboard'
+ICON = 'module-keyboard'
+TITLE = _('Keyboard')
+
diff --git a/shell/extensions/cpsection/keyboard/model.py b/shell/extensions/cpsection/keyboard/model.py
new file mode 100644
index 0000000..089c2ea
--- /dev/null
+++ b/shell/extensions/cpsection/keyboard/model.py
@@ -0,0 +1,169 @@
+# Copyright (C) 2009 OLPC
+# Author: Sayamindu Dasgupta <sayamindu@laptop.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import xklavier
+import gconf
+
+
+_GROUP_NAME = 'grp' # The XKB name for group switch options
+
+_LAYOUTS_KEY = '/desktop/sugar/peripherals/keyboard/layouts'
+_OPTIONS_KEY = '/desktop/sugar/peripherals/keyboard/options'
+_MODEL_KEY = '/desktop/sugar/peripherals/keyboard/model'
+
+class KeyboardManager(object):
+ def __init__(self, display):
+ self._engine = xklavier.Engine(display)
+ self._configregistry = xklavier.ConfigRegistry(self._engine)
+ self._configregistry.load(False)
+ self._configrec = xklavier.ConfigRec()
+ self._configrec.get_from_server(self._engine)
+
+ self._gconf_client = gconf.client_get_default()
+
+ def _populate_one(self, config_registry, item, store):
+ store.append([item.get_description(), item.get_name()])
+
+ def _populate_two(self, config_registry, item, subitem, store):
+ layout = item.get_name()
+ if subitem:
+ description = '%s, %s' % (subitem.get_description(), \
+ item.get_description())
+ variant = subitem.get_name()
+ else:
+ description = 'Default layout, %s' % item.get_description()
+ variant = ''
+
+ store.append([description, ('%s(%s)' % (layout, variant))])
+
+ def get_models(self):
+ """Return list of supported keyboard models"""
+ models = []
+ self._configregistry.foreach_model(self._populate_one, models)
+ models.sort()
+ return models
+
+ def get_languages(self):
+ """Return list of supported keyboard languages"""
+ languages = []
+ self._configregistry.foreach_language(self._populate_one, languages)
+ languages.sort()
+ return languages
+
+ def get_layouts_for_language(self, language):
+ """Return list of supported keyboard layouts for a given language"""
+ layouts = []
+ self._configregistry.foreach_language_variant(language, \
+ self._populate_two, layouts)
+ layouts.sort()
+ return layouts
+
+ def get_options_group(self):
+ """Return list of supported options for switching keyboard group"""
+ options = []
+ self._configregistry.foreach_option(_GROUP_NAME, self._populate_one, \
+ options)
+ options.sort()
+ return options
+
+ def get_current_model(self):
+ """Return the enabled keyboard model"""
+ model = self._gconf_client.get_string(_MODEL_KEY)
+ if model:
+ return model
+ else:
+ model = self._configrec.get_model()
+ self.set_model(model)
+ return model
+
+ def get_current_layouts(self):
+ """Return the enabled keyboard layouts with variants"""
+ layouts = self._gconf_client.get_list(_LAYOUTS_KEY, gconf.VALUE_STRING)
+ if layouts:
+ return layouts
+
+ layouts = self._configrec.get_layouts()
+ variants = self._configrec.get_variants()
+
+ layout_list = []
+ i = 0
+ for layout in layouts:
+ if len(variants) <= i or variants[i] == '':
+ layout_list.append('%s(%s)' % (layout, ''))
+ else:
+ layout_list.append('%s(%s)' % (layout, variants[i]))
+ i += 1
+
+ self.set_layouts(layout_list)
+
+ return layout_list
+
+ def get_current_option_group(self):
+ """Return the enabled option for switching keyboard group"""
+ options = self._gconf_client.get_list(_OPTIONS_KEY, gconf.VALUE_STRING)
+
+ if not options:
+ options = self._configrec.get_options()
+ self.set_option_group(options)
+
+ for option in options:
+ if option.startswith(_GROUP_NAME):
+ return option
+
+ return None
+
+ def get_max_layouts(self):
+ """Return the maximum number of layouts supported simultaneously"""
+ return self._engine.get_max_num_groups()
+
+ def set_model(self, model):
+ """Sets the supplied keyboard model"""
+ if model is None or not model:
+ return
+ self._gconf_client.set_string(_MODEL_KEY, model)
+ self._configrec.set_model(model)
+ self._configrec.activate(self._engine)
+
+ def set_option_group(self, option_group):
+ """Sets the supplied option for switching keyboard group"""
+ #XXX: Merge, not overwrite previous options
+ if not option_group:
+ options = ['']
+ elif isinstance(option_group, list):
+ options = option_group
+ else:
+ options = [option_group]
+ self._gconf_client.set_list(_OPTIONS_KEY, gconf.VALUE_STRING, options)
+ self._configrec.set_options(options)
+ self._configrec.activate(self._engine)
+
+ def set_layouts(self, layouts):
+ """Sets the supplied keyboard layouts (with variants)"""
+ if layouts is None or not layouts:
+ return
+ self._gconf_client.set_list(_LAYOUTS_KEY, gconf.VALUE_STRING, layouts)
+ layouts_list = []
+ variants_list = []
+ for layout in layouts:
+ layouts_list.append(layout.split('(')[0])
+ variants_list.append(layout.split('(')[1][:-1])
+
+ self._configrec.set_layouts(layouts_list)
+ self._configrec.set_variants(variants_list)
+ self._configrec.activate(self._engine)
+
diff --git a/shell/extensions/cpsection/keyboard/view.py b/shell/extensions/cpsection/keyboard/view.py
new file mode 100644
index 0000000..dd62a85
--- /dev/null
+++ b/shell/extensions/cpsection/keyboard/view.py
@@ -0,0 +1,426 @@
+# Copyright (C) 2009, OLPC
+# Author: Sayamindu Dasgupta <sayamindu@laptop.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gobject
+import pango
+import logging
+from gettext import gettext as _
+
+from sugar.graphics import style
+from sugar.graphics.icon import Icon
+
+from jarabe.controlpanel.sectionview import SectionView
+
+CLASS = 'Language'
+ICON = 'module-keyboard'
+TITLE = _('Keyboard')
+
+_APPLY_TIMEOUT = 500
+
+#TODO: This cpsection adds checks for xklavier in bin/sugar-session and
+# src/jarabe/controlpanel/gui.py. We should get rid of these checks
+# once python-xklavier has been packaged for all major distributions
+# For more information, see: http://dev.sugarlabs.org/ticket/407
+
+class LayoutCombo(gtk.HBox):
+
+ """
+ Custom GTK widget with two comboboxes side by side, one for layout, and
+ the other for variants for the selected layout.
+ """
+
+ __gsignals__ = {
+ 'selection-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_STRING, gobject.TYPE_INT))
+ }
+
+ def __init__(self, keyboard_manager, n):
+ gtk.HBox.__init__(self)
+ self._keyboard_manager = keyboard_manager
+ self._index = n
+
+ self.set_border_width(style.DEFAULT_SPACING)
+ self.set_spacing(style.DEFAULT_SPACING)
+
+ label = gtk.Label(' <b>%s</b> ' % str(n+1))
+ label.set_use_markup(True)
+ label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ label.set_alignment(0.5, 0.5)
+ self.pack_start(label, expand=False)
+
+ self._klang_store = gtk.ListStore(gobject.TYPE_STRING, \
+ gobject.TYPE_STRING)
+ for description, name in self._keyboard_manager.get_languages():
+ self._klang_store.append([name, description])
+
+ self._klang_combo = gtk.ComboBox(model = self._klang_store)
+ self._klang_combo_changed_id = \
+ self._klang_combo.connect('changed', self._klang_combo_changed_cb)
+ cell = gtk.CellRendererText()
+ cell.props.ellipsize = pango.ELLIPSIZE_MIDDLE
+ cell.props.ellipsize_set = True
+ self._klang_combo.pack_start(cell)
+ self._klang_combo.add_attribute(cell, 'text', 1)
+ self.pack_start(self._klang_combo, expand=True, fill = True)
+
+ self._kvariant_store = None
+ self._kvariant_combo = gtk.ComboBox(model = None)
+ self._kvariant_combo_changed_id = \
+ self._kvariant_combo.connect('changed', \
+ self._kvariant_combo_changed_cb)
+ cell = gtk.CellRendererText()
+ cell.props.ellipsize = pango.ELLIPSIZE_MIDDLE
+ cell.props.ellipsize_set = True
+ self._kvariant_combo.pack_start(cell)
+ self._kvariant_combo.add_attribute(cell, 'text', 1)
+ self.pack_start(self._kvariant_combo, expand=True, fill = True)
+
+ self._klang_combo.set_active(self._index)
+
+ def select_layout(self, layout):
+ """Select a given keyboard layout and show appropriate variants"""
+ self._kvariant_combo.handler_block(self._kvariant_combo_changed_id)
+ for i in range(0, len(self._klang_store)):
+ self._klang_combo.set_active(i)
+ for j in range(0, len(self._kvariant_store)):
+ if self._kvariant_store[j][0] == layout:
+ self._kvariant_combo.set_active(j)
+ self._kvariant_combo.handler_unblock(\
+ self._kvariant_combo_changed_id)
+ return True
+
+ self._kvariant_combo.handler_unblock(self._kvariant_combo_changed_id)
+ self._klang_combo.set_active(0)
+ return False
+
+ def get_layout(self):
+ """Gets the selected layout (with variant)"""
+ it = self._kvariant_combo.get_active_iter()
+ model = self._kvariant_combo.get_model()
+ return model.get(it, 0)[0]
+
+ def _set_kvariant_store(self, lang):
+ self._kvariant_store = gtk.ListStore(gobject.TYPE_STRING, \
+ gobject.TYPE_STRING)
+ layouts = self._keyboard_manager.get_layouts_for_language(lang)
+ for description, name in layouts:
+ self._kvariant_store.append([name, description])
+ self._kvariant_combo.set_model(self._kvariant_store)
+ self._kvariant_combo.set_active(0)
+
+ def _klang_combo_changed_cb(self, combobox):
+ it = combobox.get_active_iter()
+ model = combobox.get_model()
+ lang = model.get(it, 0)[0]
+ self._set_kvariant_store(lang)
+
+ def _kvariant_combo_changed_cb(self, combobox):
+ it = combobox.get_active_iter()
+ model = combobox.get_model()
+ layout = model.get(it, 0)[0]
+ self.emit('selection-changed', layout, self._index)
+
+
+class Keyboard(SectionView):
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = model
+
+ self._kmodel = None
+ self._selected_kmodel = None
+
+ self._klayouts = []
+ self._selected_klayouts = []
+
+ self._group_switch_option = None
+ self._selected_group_switch_option = None
+
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+ self.set_spacing(style.DEFAULT_SPACING)
+
+ self._layout_table = gtk.Table(rows = 4, columns = 2, \
+ homogeneous = False)
+
+ self._keyboard_manager = model.KeyboardManager(self.get_display())
+ self._layout_combo_list = []
+ self._layout_addremovebox_list = []
+
+ scrollwindow = gtk.ScrolledWindow()
+ scrollwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.pack_start(scrollwindow, expand=True)
+ scrollwindow.show()
+
+ self._vbox = gtk.VBox()
+ scrollwindow.add_with_viewport(self._vbox)
+
+ self.__kmodel_sid = None
+ self.__layout_sid = None
+ self.__group_switch_sid = None
+
+ self._setup_kmodel()
+ self._setup_layouts()
+ self._setup_group_switch_option()
+
+ self._vbox.show()
+
+ def _setup_kmodel(self):
+ """Adds the controls for changing the keyboard model"""
+ separator_kmodel = gtk.HSeparator()
+ self._vbox.pack_start(separator_kmodel, expand=False)
+ separator_kmodel.show_all()
+
+ label_kmodel = gtk.Label(_('Keyboard Model'))
+ label_kmodel.set_alignment(0, 0)
+ self._vbox.pack_start(label_kmodel, expand=False)
+ label_kmodel.show_all()
+
+ box_kmodel = gtk.VBox()
+ box_kmodel.set_border_width(style.DEFAULT_SPACING * 2)
+ box_kmodel.set_spacing(style.DEFAULT_SPACING)
+
+ kmodel_store = gtk.ListStore(gobject.TYPE_STRING, \
+ gobject.TYPE_STRING)
+ for description, name in self._keyboard_manager.get_models():
+ kmodel_store.append([name, description])
+
+ kmodel_combo = gtk.ComboBox(model = kmodel_store)
+ cell = gtk.CellRendererText()
+ cell.props.ellipsize = pango.ELLIPSIZE_MIDDLE
+ cell.props.ellipsize_set = True
+ kmodel_combo.pack_start(cell)
+ kmodel_combo.add_attribute(cell, 'text', 1)
+
+ self._kmodel = self._keyboard_manager.get_current_model()
+ if self._kmodel is not None:
+ for row in kmodel_store:
+ if self._kmodel in row[0]:
+ kmodel_combo.set_active_iter(row.iter)
+ break
+
+ box_kmodel.pack_start(kmodel_combo, expand = False)
+ self._vbox.pack_start(box_kmodel, expand=False)
+ box_kmodel.show_all()
+
+ kmodel_combo.connect('changed', self.__kmodel_changed_cb)
+
+ def __kmodel_changed_cb(self, combobox):
+ if self.__kmodel_sid is not None:
+ gobject.source_remove(self.__kmodel_sid)
+ self.__kmodel_sid = gobject.timeout_add(_APPLY_TIMEOUT,
+ self.__kmodel_timeout_cb, combobox)
+
+ def __kmodel_timeout_cb(self, combobox):
+ it = combobox.get_active_iter()
+ model = combobox.get_model()
+ self._selected_kmodel = model.get(it, 0)[0]
+ if self._selected_kmodel == self._keyboard_manager.get_current_model():
+ return
+ try:
+ self._keyboard_manager.set_model(self._selected_kmodel)
+ except Exception:
+ logging.exception('Could not set new keyboard model')
+
+ return False
+
+ def _setup_group_switch_option(self):
+ """Adds the controls for changing the group switch option of keyboard"""
+ separator_group_option = gtk.HSeparator()
+ self._vbox.pack_start(separator_group_option, expand=False)
+ separator_group_option.show_all()
+
+ label_group_option = gtk.Label(_('Key(s) to change layout'))
+ label_group_option.set_alignment(0, 0)
+ self._vbox.pack_start(label_group_option, expand=False)
+ label_group_option.show_all()
+
+ box_group_option = gtk.VBox()
+ box_group_option.set_border_width(style.DEFAULT_SPACING * 2)
+ box_group_option.set_spacing(style.DEFAULT_SPACING)
+
+ group_option_store = gtk.ListStore(gobject.TYPE_STRING, \
+ gobject.TYPE_STRING)
+ for description, name in self._keyboard_manager.get_options_group():
+ group_option_store.append([name, description])
+
+ group_option_combo = gtk.ComboBox(model = group_option_store)
+ cell = gtk.CellRendererText()
+ cell.props.ellipsize = pango.ELLIPSIZE_MIDDLE
+ cell.props.ellipsize_set = True
+ group_option_combo.pack_start(cell)
+ group_option_combo.add_attribute(cell, 'text', 1)
+
+ self._group_switch_option = \
+ self._keyboard_manager.get_current_option_group()
+ if not self._group_switch_option:
+ group_option_combo.set_active(0)
+ else:
+ found = False
+ for row in group_option_store:
+ if self._group_switch_option in row[0]:
+ group_option_combo.set_active_iter(row.iter)
+ found = True
+ break
+ if not found:
+ group_option_combo.set_active(0)
+
+ box_group_option.pack_start(group_option_combo, expand = False)
+ self._vbox.pack_start(box_group_option, expand=False)
+ box_group_option.show_all()
+
+ group_option_combo.connect('changed', \
+ self.__group_switch_changed_cb)
+
+ def __group_switch_changed_cb(self, combobox):
+ if self.__group_switch_sid is not None:
+ gobject.source_remove(self.__group_switch_sid)
+ self.__group_switch_sid = gobject.timeout_add(_APPLY_TIMEOUT,
+ self.__group_switch_timeout_cb, combobox)
+
+ def __group_switch_timeout_cb(self, combobox):
+ it = combobox.get_active_iter()
+ model = combobox.get_model()
+ self._selected_group_switch_option = model.get(it, 0)[0]
+ if self._selected_group_switch_option == \
+ self._keyboard_manager.get_current_option_group():
+ return
+ try:
+ self._keyboard_manager.set_option_group(\
+ self._selected_group_switch_option)
+ except Exception:
+ logging.exception('Could not set new keyboard group switch option')
+
+
+ return False
+
+ def _setup_layouts(self):
+ """Adds the controls for changing the keyboard layouts"""
+ separator_klayout = gtk.HSeparator()
+ self._vbox.pack_start(separator_klayout, expand=False)
+ separator_klayout.show_all()
+
+ label_klayout = gtk.Label(_('Keyboard Layout(s)'))
+ label_klayout.set_alignment(0, 0)
+ label_klayout.show_all()
+ self._vbox.pack_start(label_klayout, expand=False)
+
+ self._klayouts = self._keyboard_manager.get_current_layouts()
+ for i in range(0, self._keyboard_manager.get_max_layouts()):
+ add_remove_box = self.__create_add_remove_box()
+ self._layout_addremovebox_list.append(add_remove_box)
+ self._layout_table.attach(add_remove_box, 1, 2, i, i+1)
+
+ layout_combo = LayoutCombo(self._keyboard_manager, i)
+ layout_combo.connect('selection-changed', \
+ self.__layout_combo_selection_changed_cb)
+ self._layout_combo_list.append(layout_combo)
+ self._layout_table.attach(layout_combo, 0, 1, i, i+1)
+
+ if i < len(self._klayouts):
+ layout_combo.show_all()
+ layout_combo.select_layout(self._klayouts[i])
+
+ self._vbox.pack_start(self._layout_table, expand=False)
+ self._layout_table.set_size_request(self._vbox.size_request()[0], -1)
+ self._layout_table.show()
+ self._update_klayouts()
+
+ def __determine_add_remove_box_visibility(self):
+ i = 1
+ for box in self._layout_addremovebox_list:
+ if not i == len(self._selected_klayouts):
+ box.props.visible = False
+ else:
+ box.show_all()
+ if i == 1:
+ # First row - no need for showing remove btn
+ add, remove = box.get_children()
+ remove.props.visible = False
+ if i == self._keyboard_manager.get_max_layouts():
+ # Last row - no need for showing add btn
+ add, remove = box.get_children()
+ add.props.visible = False
+ i += 1
+
+ def __create_add_remove_box(self):
+ '''Creates gtk.Hbox with add/remove buttons'''
+ add_icon = Icon(icon_name='list-add')
+
+ add_button = gtk.Button()
+ add_button.set_image(add_icon)
+ add_button.connect('clicked',
+ self.__add_button_clicked_cb)
+
+ remove_icon = Icon(icon_name='list-remove')
+ remove_button = gtk.Button()
+ remove_button.set_image(remove_icon)
+ remove_button.connect('clicked',
+ self.__remove_button_clicked_cb)
+
+ add_remove_box = gtk.HButtonBox()
+ add_remove_box.set_layout(gtk.BUTTONBOX_START)
+ add_remove_box.set_spacing(10)
+ add_remove_box.pack_start(add_button)
+ add_remove_box.pack_start(remove_button)
+
+ return add_remove_box
+
+ def __layout_combo_selection_changed_cb(self, combo, layout, index):
+ self._update_klayouts()
+
+ def __add_button_clicked_cb(self, button):
+ self._layout_combo_list[len(self._selected_klayouts)].show_all()
+ self._update_klayouts()
+
+ def __remove_button_clicked_cb(self, button):
+ self._layout_combo_list[len(self._selected_klayouts) - 1].hide()
+ self._update_klayouts()
+
+ def _update_klayouts(self):
+ """Responds to any changes in the keyboard layout options"""
+ self._selected_klayouts = []
+ for combo in self._layout_combo_list:
+ if combo.props.visible:
+ self._selected_klayouts.append(combo.get_layout())
+
+ self.__determine_add_remove_box_visibility()
+
+ if self.__layout_sid is not None:
+ gobject.source_remove(self.__layout_sid)
+ self.__layout_sid = gobject.timeout_add(_APPLY_TIMEOUT,
+ self.__layout_timeout_cb)
+
+ def __layout_timeout_cb(self):
+ if self._selected_klayouts == \
+ self._keyboard_manager.get_current_layouts():
+ return
+ try:
+ self._keyboard_manager.set_layouts(self._selected_klayouts)
+ except Exception:
+ logging.exception('Could not set new keyboard layouts')
+
+ return False
+
+
+ def undo(self):
+ """Reverts back to the original keyboard configuration"""
+ self._keyboard_manager.set_model(self._kmodel)
+ self._keyboard_manager.set_layouts(self._klayouts)
+ self._keyboard_manager.set_option_group(self._group_switch_option)
+
diff --git a/shell/extensions/cpsection/language/Makefile.am b/shell/extensions/cpsection/language/Makefile.am
new file mode 100644
index 0000000..209fc32
--- /dev/null
+++ b/shell/extensions/cpsection/language/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/language
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/language/__init__.py b/shell/extensions/cpsection/language/__init__.py
new file mode 100644
index 0000000..a8f9f08
--- /dev/null
+++ b/shell/extensions/cpsection/language/__init__.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+CLASS = 'Language'
+ICON = 'module-language'
+TITLE = _('Language')
+
diff --git a/shell/extensions/cpsection/language/model.py b/shell/extensions/cpsection/language/model.py
new file mode 100644
index 0000000..4f3686f
--- /dev/null
+++ b/shell/extensions/cpsection/language/model.py
@@ -0,0 +1,151 @@
+# Copyright (C) 2007, 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+#
+# The language config is based on the system-config-language
+# (http://fedoraproject.org/wiki/SystemConfig/language) tool
+# Parts of the code were reused.
+#
+
+import os
+import locale
+from gettext import gettext as _
+import subprocess
+
+_default_lang = '%s.%s' % locale.getdefaultlocale()
+_standard_msg = _("Could not access ~/.i18n. Create standard settings.")
+
+def read_all_languages():
+ fdp = subprocess.Popen(['locale', '-av'], stdout=subprocess.PIPE)
+ lines = fdp.stdout.read().split('\n')
+ locales = []
+
+ for line in lines:
+ if line.find('locale:') != -1:
+ locale = line.split()[1]
+ elif line.find('language |') != -1:
+ lang = line.lstrip('language |')
+ elif line.find('territory |') != -1:
+ territory = line.lstrip('territory |')
+ if locale.endswith('utf8') and len(lang):
+ locales.append((lang, territory, locale))
+
+ #FIXME: This is a temporary workaround for locales that are essential to
+ # OLPC, but are not in Glibc yet.
+ locales.append(('Kreyol', 'Haiti', 'ht_HT.utf8'))
+ locales.append(('Dari', 'Afghanistan', 'fa_AF.utf8'))
+ locales.append(('Pashto', 'Afghanistan', 'ps_AF.utf8'))
+
+ locales.sort()
+ return locales
+
+def _initialize():
+ if set_languages.__doc__ is None:
+ # when running under 'python -OO', all __doc__ fields are None,
+ # so += would fail -- and this function would be unnecessary anyway.
+ return
+ languages = read_all_languages()
+ set_languages.__doc__ += '\n'
+ for lang in languages:
+ set_languages.__doc__ += '%s \n' % (lang[0].replace(' ', '_') + '/' +
+ lang[1].replace(' ', '_'))
+
+def _write_i18n(langs):
+ colon = ':'
+ langstr = colon.join(langs)
+ path = os.path.join(os.environ.get("HOME"), '.i18n')
+ if not os.access(path, os.W_OK):
+ print _standard_msg
+ fd = open(path, 'w')
+ fd.write('LANG="%s"\n' % _default_lang)
+ fd.write('LANGUAGE="%s"\n' % _default_lang)
+ fd.close()
+ else:
+ fd = open(path, 'w')
+ fd.write('LANG="%s"\n' % langs[0].strip("\n"))
+ fd.write('LANGUAGE="%s"\n' % langstr)
+ fd.close()
+
+def get_languages():
+ path = os.path.join(os.environ.get("HOME"), '.i18n')
+ if not os.access(path, os.R_OK):
+ print _standard_msg
+ fd = open(path, 'w')
+ fd.write('LANG="%s"\n' % _default_lang)
+ fd.write('LANGUAGE="%s"\n' % _default_lang)
+ fd.close()
+ return [_default_lang]
+
+ fd = open(path, "r")
+ lines = fd.readlines()
+ fd.close()
+
+ langlist = None
+
+ for line in lines:
+ if line.startswith("LANGUAGE="):
+ lang = line[9:].replace('"', '')
+ lang = lang.strip()
+ langlist = lang.split(':')
+ elif line.startswith("LANG="):
+ lang = line[5:].replace('"', '')
+
+ # There might be cases where .i18n may not contain a LANGUAGE field
+ if langlist == None:
+ return [lang]
+ else:
+ return langlist
+
+def print_languages():
+ codes = get_languages()
+
+ languages = read_all_languages()
+ for code in codes:
+ found_lang = False
+ for lang in languages:
+ if lang[2].split('.')[0] == code.split('.')[0]:
+ print lang[0].replace(' ', '_') + '/' + \
+ lang[1].replace(' ', '_')
+ found_lang = True
+ break
+ if not found_lang:
+ print (_("Language for code=%s could not be determined.") % code)
+
+def set_languages(languages):
+ """Set the system language.
+ languages :
+ """
+ if isinstance(languages, str):
+ # This came from the commandline
+ #TODO: Support multiple languages from the command line
+ if languages.endswith('utf8'):
+ _write_i18n(languages)
+ return 1
+ else:
+ langs = read_all_languages()
+ for lang, territory, locale in langs:
+ code = lang.replace(' ', '_') + '/' \
+ + territory.replace(' ', '_')
+ if code == languages:
+ _write_i18n(locale)
+ return 1
+ print (_("Sorry I do not speak \'%s\'.") % languages)
+ else:
+ _write_i18n(languages)
+
+# inilialize the docstrings for the language
+_initialize()
+
diff --git a/shell/extensions/cpsection/language/view.py b/shell/extensions/cpsection/language/view.py
new file mode 100644
index 0000000..d1a49cf
--- /dev/null
+++ b/shell/extensions/cpsection/language/view.py
@@ -0,0 +1,282 @@
+# Copyright (C) 2008, OLPC
+# Copyright (C) 2009, Simon Schampijer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gobject
+import gettext
+
+from sugar.graphics import style
+from sugar.graphics.icon import Icon
+
+from jarabe.controlpanel.sectionview import SectionView
+from jarabe.controlpanel.inlinealert import InlineAlert
+
+_translate_language = lambda msg: gettext.dgettext('iso_639', msg)
+_translate_country = lambda msg: gettext.dgettext('iso_3166', msg)
+
+CLASS = 'Language'
+ICON = 'module-language'
+TITLE = gettext.gettext('Language')
+
+class Language(SectionView):
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = model
+ self.restart_alerts = alerts
+ self._lang_sid = 0
+ self._selected_lang_count = 0
+ self._labels = []
+ self._stores = []
+ self._comboboxes = []
+ self._add_remove_boxes = []
+ self._changed = False
+ self._cursor_change_handler = None
+
+ self._available_locales = self._model.read_all_languages()
+ self._selected_locales = self._model.get_languages()
+
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+ self.set_spacing(style.DEFAULT_SPACING)
+
+ explanation = gettext.gettext("Add languages in the order you prefer." \
+ " If a translation is not available,"\
+ " the next in the list will be used.")
+ self._text = gtk.Label(explanation)
+ self._text.set_width_chars(100)
+ self._text.set_line_wrap(True)
+ self._text.set_alignment(0, 0)
+ self.pack_start(self._text, False)
+ self._text.show()
+
+ scrolled = gtk.ScrolledWindow()
+ scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ scrolled.show()
+ self.pack_start(scrolled, expand=True)
+
+ self._table = gtk.Table(rows=1, columns=3, homogeneous=False)
+ self._table.set_border_width(style.DEFAULT_SPACING * 2)
+ self._table.show()
+ scrolled.add_with_viewport(self._table)
+
+ self._lang_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self.pack_start(self._lang_alert_box, False)
+
+ self._lang_alert = InlineAlert()
+ self._lang_alert_box.pack_start(self._lang_alert)
+ if 'lang' in self.restart_alerts:
+ self._lang_alert.props.msg = self.restart_msg
+ self._lang_alert.show()
+ self._lang_alert_box.show()
+
+ self.setup()
+
+ def _add_row(self, locale_code=None):
+ '''Adds a row to the table'''
+
+ self._selected_lang_count += 1
+
+ self._table.resize(self._selected_lang_count, 3)
+
+ label = gtk.Label(str=str(self._selected_lang_count))
+ label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ self._labels.append(label)
+ self._attach_to_table(label, 0, 1, padding=1)
+ label.show()
+
+
+ store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
+ for language, country, code in self._available_locales:
+ description = '%s (%s)' % (_translate_language(language), \
+ _translate_country(country))
+ store.append([code, description])
+
+ combobox = gtk.ComboBox(model=store)
+ cell = gtk.CellRendererText()
+ combobox.pack_start(cell)
+ combobox.add_attribute(cell, 'text', 1)
+
+ if locale_code:
+ for row in store:
+ lang = locale_code.split('.')[0]
+ lang_column = row[0].split('.')[0]
+ if lang in lang_column:
+ combobox.set_active_iter(row.iter)
+ break
+ else:
+ combobox.set_active(1)
+
+ combobox.connect('changed', self.__combobox_changed_cb)
+
+ self._stores.append(store)
+ self._comboboxes.append(combobox)
+ self._attach_to_table(combobox, 1, 2, yoptions=gtk.SHRINK)
+
+ add_remove_box = self._create_add_remove_box()
+ self._add_remove_boxes.append(add_remove_box)
+ self._attach_to_table(add_remove_box, 2, 3)
+
+ add_remove_box.show_all()
+
+ if self._selected_lang_count > 1:
+ previous_add_removes = self._add_remove_boxes[-2]
+ previous_add_removes.hide_all()
+
+ self._determine_add_remove_visibility()
+
+ combobox.show()
+
+ def _attach_to_table(self, widget, row, column, padding=20, \
+ yoptions=gtk.FILL):
+ self._table.attach(widget, row, column, \
+ self._selected_lang_count - 1, self._selected_lang_count, \
+ xoptions=gtk.FILL, yoptions=yoptions, xpadding=padding, \
+ ypadding=padding)
+
+ def _delete_last_row(self):
+ '''Deletes the last row of the table'''
+
+ self._selected_lang_count -= 1
+
+ label, add_remove_box, combobox, store_ = self._get_last_row()
+
+ label.destroy()
+ add_remove_box.destroy()
+ combobox.destroy()
+
+ self._table.resize(self._selected_lang_count, 3)
+
+ self._add_remove_boxes[-1].show_all()
+
+ def _get_last_row(self):
+ label = self._labels.pop()
+ add_remove_box = self._add_remove_boxes.pop()
+ combobox = self._comboboxes.pop()
+ store = self._stores.pop()
+
+ return label, add_remove_box, combobox, store
+
+ def setup(self):
+ for locale in self._selected_locales:
+ self._add_row(locale_code=locale)
+
+ def undo(self):
+ self._model.undo()
+ self._lang_alert.hide()
+
+ def _create_add_remove_box(self):
+ '''Creates gtk.Hbox with add/remove buttons'''
+ add_icon = Icon(icon_name='list-add')
+
+ add_button = gtk.Button()
+ add_button.set_image(add_icon)
+ add_button.connect('clicked',
+ self.__add_button_clicked_cb)
+
+ remove_icon = Icon(icon_name='list-remove')
+ remove_button = gtk.Button()
+ remove_button.set_image(remove_icon)
+ remove_button.connect('clicked',
+ self.__remove_button_clicked_cb)
+
+ add_remove_box = gtk.HButtonBox()
+ add_remove_box.set_layout(gtk.BUTTONBOX_START)
+ add_remove_box.set_spacing(10)
+ add_remove_box.pack_start(add_button)
+ add_remove_box.pack_start(remove_button)
+
+ return add_remove_box
+
+ def __add_button_clicked_cb(self, button):
+ self._add_row()
+ self._check_change()
+
+ def __remove_button_clicked_cb(self, button):
+ self._delete_last_row()
+ self._check_change()
+
+ def __combobox_changed_cb(self, button):
+ self._check_change()
+
+ def _check_change(self):
+ selected_langs = self._get_selected_langs()
+ last_lang = selected_langs[-1]
+
+ self._determine_add_remove_visibility(last_lang = last_lang)
+
+ self._changed = (selected_langs != self._selected_locales)
+
+ if self._changed == False:
+ # The user reverted back to the original config
+ self.needs_restart = False
+ if 'lang' in self.restart_alerts:
+ self.restart_alerts.remove('lang')
+ self._lang_alert.hide()
+ if self._lang_sid:
+ gobject.source_remove(self._lang_sid)
+ self._model.undo()
+ return False
+
+ if self._lang_sid:
+ gobject.source_remove(self._lang_sid)
+ self._lang_sid = gobject.timeout_add(self._APPLY_TIMEOUT,
+ self.__lang_timeout_cb,
+ selected_langs)
+
+ def _get_selected_langs(self):
+ new_codes = []
+ for combobox in self._comboboxes:
+ it = combobox.get_active_iter()
+ model = combobox.get_model()
+ lang_code = model.get(it, 0)[0]
+ new_codes.append(lang_code)
+
+ return new_codes
+
+ def _determine_add_remove_visibility(self, last_lang = None):
+ # We should not let users add fallback languages for English (USA)
+ # This is because the software is not usually _translated_ into English
+ # which means that the fallback gets selected automatically
+
+ if last_lang is None:
+ selected_langs = self._get_selected_langs()
+ last_lang = selected_langs[-1]
+
+ add_remove_box = self._add_remove_boxes[-1]
+ buttons = add_remove_box.get_children()
+ add_button, remove_button = buttons
+
+ if last_lang.startswith('en_US'):
+ add_button.props.visible = False
+ else:
+ add_button.props.visible = True
+
+ if self._selected_lang_count == 1:
+ remove_button.props.visible = False
+ else:
+ remove_button.props.visible = True
+
+
+ def __lang_timeout_cb(self, codes):
+ self._lang_sid = 0
+ self._model.set_languages(codes)
+ self.restart_alerts.append('lang')
+ self.needs_restart = True
+ self._lang_alert.props.msg = self.restart_msg
+ self._lang_alert.show()
+ return False
diff --git a/shell/extensions/cpsection/modemconfiguration/Makefile.am b/shell/extensions/cpsection/modemconfiguration/Makefile.am
new file mode 100644
index 0000000..3e2613e
--- /dev/null
+++ b/shell/extensions/cpsection/modemconfiguration/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/modemconfiguration
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/modemconfiguration/__init__.py b/shell/extensions/cpsection/modemconfiguration/__init__.py
new file mode 100644
index 0000000..8a219dc
--- /dev/null
+++ b/shell/extensions/cpsection/modemconfiguration/__init__.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 US
+
+from gettext import gettext as _
+
+CLASS = 'ModemConfiguration'
+ICON = 'module-modemconfiguration'
+TITLE = _('Modem Configuration')
+
diff --git a/shell/extensions/cpsection/modemconfiguration/model.py b/shell/extensions/cpsection/modemconfiguration/model.py
new file mode 100755
index 0000000..2545ce1
--- /dev/null
+++ b/shell/extensions/cpsection/modemconfiguration/model.py
@@ -0,0 +1,70 @@
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 US
+
+import gconf
+
+from jarabe.model.network import GSM_USERNAME_PATH, GSM_PASSWORD_PATH, \
+ GSM_NUMBER_PATH, GSM_APN_PATH, GSM_PIN_PATH, \
+ GSM_PUK_PATH
+
+def get_username():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_USERNAME_PATH) or ''
+
+def get_password():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_PASSWORD_PATH) or ''
+
+def get_number():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_NUMBER_PATH) or ''
+
+def get_apn():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_APN_PATH) or ''
+
+def get_pin():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_PIN_PATH) or ''
+
+def get_puk():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_PUK_PATH) or ''
+
+def set_username(username):
+ client = gconf.client_get_default()
+ client.set_string(GSM_USERNAME_PATH, username)
+
+def set_password(password):
+ client = gconf.client_get_default()
+ client.set_string(GSM_PASSWORD_PATH, password)
+
+def set_number(number):
+ client = gconf.client_get_default()
+ client.set_string(GSM_NUMBER_PATH, number)
+
+def set_apn(apn):
+ client = gconf.client_get_default()
+ client.set_string(GSM_APN_PATH, apn)
+
+def set_pin(pin):
+ client = gconf.client_get_default()
+ client.set_string(GSM_PIN_PATH, pin)
+
+def set_puk(puk):
+ client = gconf.client_get_default()
+ client.set_string(GSM_PUK_PATH, puk)
+
diff --git a/shell/extensions/cpsection/modemconfiguration/view.py b/shell/extensions/cpsection/modemconfiguration/view.py
new file mode 100644
index 0000000..b236f3f
--- /dev/null
+++ b/shell/extensions/cpsection/modemconfiguration/view.py
@@ -0,0 +1,250 @@
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 US
+
+import os
+import logging
+from gettext import gettext as _
+
+import gtk
+import gobject
+
+from sugar.graphics import style
+
+from jarabe.controlpanel.sectionview import SectionView
+
+APPLY_TIMEOUT = 1000
+
+class EntryWithLabel(gtk.HBox):
+ __gtype_name__ = "SugarEntryWithLabel"
+
+ def __init__(self, label_text):
+ gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING)
+
+ self._timeout_sid = 0
+ self._changed_handler = None
+ self._is_valid = True
+
+ self.label = gtk.Label(label_text)
+ self.label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ self.label.set_alignment(1, 0.5)
+ self.pack_start(self.label, expand=False)
+ self.label.show()
+
+ self._entry = gtk.Entry(25)
+ self._entry.connect('changed', self.__entry_changed_cb)
+ self._entry.set_width_chars(25)
+ self.pack_start(self._entry, expand=False)
+ self._entry.show()
+
+ def __entry_changed_cb(self, widget, data=None):
+ if self._timeout_sid:
+ gobject.source_remove(self._timeout_sid)
+ self._timeout_sid = gobject.timeout_add(APPLY_TIMEOUT,
+ self.__timeout_cb)
+
+ def __timeout_cb(self):
+ self._timeout_sid = 0
+
+ if self._entry.get_text() == self.get_value():
+ return False
+
+ try:
+ self.set_value(self._entry.get_text())
+ except ValueError:
+ self._is_valid = False
+ else:
+ self._is_valid = True
+
+ self.notify('is-valid')
+
+ return False
+
+ def set_text_from_model(self):
+ self._entry.set_text(self.get_value())
+
+ def get_value(self):
+ raise NotImplementedError
+
+ def set_value(self):
+ raise NotImplementedError
+
+ def _get_is_valid(self):
+ return self._is_valid
+ is_valid = gobject.property(type=bool, getter=_get_is_valid, default=True)
+
+class UsernameEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('Username:'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_username()
+
+ def set_value(self, username):
+ self._model.set_username(username)
+
+class PasswordEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('Password:'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_password()
+
+ def set_value(self, password):
+ self._model.set_password(password)
+
+class NumberEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('Number:'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_number()
+
+ def set_value(self, number):
+ self._model.set_number(number)
+
+class ApnEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('Access Point Name (APN):'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_apn()
+
+ def set_value(self, apn):
+ self._model.set_apn(apn)
+
+class PinEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('Personal Identity Number (PIN):'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_pin()
+
+ def set_value(self, pin):
+ self._model.set_pin(pin)
+
+class PukEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('Personal Unblocking Key (PUK):'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_puk()
+
+ def set_value(self, puk):
+ self._model.set_puk(puk)
+
+
+class ModemConfiguration(SectionView):
+ def __init__(self, model, alerts=None):
+ SectionView.__init__(self)
+
+ self._model = model
+ self.restart_alerts = alerts
+
+ self.set_border_width(style.DEFAULT_SPACING)
+ self.set_spacing(style.DEFAULT_SPACING)
+ self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+ explanation = _("You will need to provide the following " \
+ "information to set up a mobile " \
+ "broadband connection to a cellular "\
+ "(3G) network.")
+ self._text = gtk.Label(explanation)
+ self._text.set_width_chars(100)
+ self._text.set_line_wrap(True)
+ self._text.set_alignment(0, 0)
+ self.pack_start(self._text, False)
+ self._text.show()
+
+ self._username_entry = UsernameEntry(model)
+ self._username_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self._group.add_widget(self._username_entry.label)
+ self.pack_start(self._username_entry, expand=False)
+ self._username_entry.show()
+
+ self._password_entry = PasswordEntry(model)
+ self._password_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self._group.add_widget(self._password_entry.label)
+ self.pack_start(self._password_entry, expand=False)
+ self._password_entry.show()
+
+ self._number_entry = NumberEntry(model)
+ self._number_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self._group.add_widget(self._number_entry.label)
+ self.pack_start(self._number_entry, expand=False)
+ self._number_entry.show()
+
+ self._apn_entry = ApnEntry(model)
+ self._apn_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self._group.add_widget(self._apn_entry.label)
+ self.pack_start(self._apn_entry, expand=False)
+ self._apn_entry.show()
+
+ self._pin_entry = PinEntry(model)
+ self._pin_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self._group.add_widget(self._pin_entry.label)
+ self.pack_start(self._pin_entry, expand=False)
+ self._pin_entry.show()
+
+ self._puk_entry = PukEntry(model)
+ self._puk_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self._group.add_widget(self._puk_entry.label)
+ self.pack_start(self._puk_entry, expand=False)
+ self._puk_entry.show()
+
+ self.setup()
+
+ def setup(self):
+ self._username_entry.set_text_from_model()
+ self._password_entry.set_text_from_model()
+ self._number_entry.set_text_from_model()
+ self._apn_entry.set_text_from_model()
+ self._pin_entry.set_text_from_model()
+ self._puk_entry.set_text_from_model()
+
+ self.needs_restart = False
+
+ def undo(self):
+ self._model.undo()
+
+ def _validate(self):
+ if self._username_entry.is_valid and \
+ self._password_entry.is_valid and \
+ self._number_entry.is_valid and \
+ self._apn_entry.is_valid and \
+ self._pin_entry.is_valid and \
+ self._puk_entry.is_valid:
+ self.props.is_valid = True
+ else:
+ self.props.is_valid = False
+
+ def __notify_is_valid_cb(self, entry, pspec):
+ if entry.is_valid:
+ self.needs_restart = True
+ self._validate()
+
diff --git a/shell/extensions/cpsection/network/Makefile.am b/shell/extensions/cpsection/network/Makefile.am
new file mode 100644
index 0000000..35fd27c
--- /dev/null
+++ b/shell/extensions/cpsection/network/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/network
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/network/__init__.py b/shell/extensions/cpsection/network/__init__.py
new file mode 100644
index 0000000..8fea274
--- /dev/null
+++ b/shell/extensions/cpsection/network/__init__.py
@@ -0,0 +1,25 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+CLASS = 'Network'
+ICON = 'module-network'
+TITLE = _('Network')
+KEYWORDS = ['network', 'jabber', 'radio', 'server']
+
+
+
diff --git a/shell/extensions/cpsection/network/model.py b/shell/extensions/cpsection/network/model.py
new file mode 100644
index 0000000..e1c3dab
--- /dev/null
+++ b/shell/extensions/cpsection/network/model.py
@@ -0,0 +1,141 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import dbus
+from gettext import gettext as _
+import gconf
+
+_NM_SERVICE = 'org.freedesktop.NetworkManager'
+_NM_PATH = '/org/freedesktop/NetworkManager'
+_NM_IFACE = 'org.freedesktop.NetworkManager'
+
+KEYWORDS = ['network', 'jabber', 'radio', 'server']
+
+class ReadError(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+def get_jabber():
+ client = gconf.client_get_default()
+ return client.get_string('/desktop/sugar/collaboration/jabber_server')
+
+def print_jabber():
+ print get_jabber()
+
+def set_jabber(server):
+ """Set the jabber server
+ server : e.g. 'olpc.collabora.co.uk'
+ """
+ client = gconf.client_get_default()
+ client.set_string('/desktop/sugar/collaboration/jabber_server', server)
+
+ _restart_jabber()
+ return 0
+
+def _restart_jabber():
+ """Call Sugar Presence Service to restart Telepathy CMs.
+
+ This allows restarting the jabber server connection when we change it.
+ """
+ _PS_SERVICE = "org.laptop.Sugar.Presence"
+ _PS_INTERFACE = "org.laptop.Sugar.Presence"
+ _PS_PATH = "/org/laptop/Sugar/Presence"
+ bus = dbus.SessionBus()
+ try:
+ ps = dbus.Interface(bus.get_object(_PS_SERVICE, _PS_PATH),
+ _PS_INTERFACE)
+ except dbus.DBusException:
+ raise ReadError('%s service not available' % _PS_SERVICE)
+ ps.RestartServerConnection()
+
+def get_radio():
+ try:
+ bus = dbus.SystemBus()
+ obj = bus.get_object(_NM_SERVICE, _NM_PATH)
+ nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ except dbus.DBusException:
+ raise ReadError('%s service not available' % _NM_SERVICE)
+
+ state = nm_props.Get(_NM_IFACE, 'WirelessEnabled')
+ if state in (0, 1):
+ return state
+ else:
+ raise ReadError(_('State is unknown.'))
+
+def print_radio():
+ print ('off', 'on')[get_radio()]
+
+def set_radio(state):
+ """Turn Radio 'on' or 'off'
+ state : 'on/off'
+ """
+ if state == 'on' or state == 1:
+ try:
+ bus = dbus.SystemBus()
+ obj = bus.get_object(_NM_SERVICE, _NM_PATH)
+ nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ except dbus.DBusException:
+ raise ReadError('%s service not available' % _NM_SERVICE)
+ nm_props.Set(_NM_IFACE, 'WirelessEnabled', True)
+ elif state == 'off' or state == 0:
+ try:
+ bus = dbus.SystemBus()
+ obj = bus.get_object(_NM_SERVICE, _NM_PATH)
+ nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ except dbus.DBusException:
+ raise ReadError('%s service not available' % _NM_SERVICE)
+ nm_props.Set(_NM_IFACE, 'WirelessEnabled', False)
+ else:
+ raise ValueError(_("Error in specified radio argument use on/off."))
+
+ return 0
+
+def clear_registration():
+ """Clear the registration with the schoolserver
+ """
+ client = gconf.client_get_default()
+ client.set_string('/desktop/sugar/backup_url', '')
+ return 1
+
+def clear_networks():
+ """Clear saved passwords and network configurations.
+ """
+ pass
+
+def get_publish_information():
+ client = gconf.client_get_default()
+ publish = client.get_bool('/desktop/sugar/collaboration/publish_gadget')
+ return publish
+
+def print_publish_information():
+ print get_publish_information()
+
+def set_publish_information(value):
+ """ If set to true, Sugar will make you searchable for
+ the other users of the Jabber server.
+ value: 0/1
+ """
+ try:
+ value = (False, True)[int(value)]
+ except:
+ raise ValueError(_("Error in specified argument use 0/1."))
+
+ client = gconf.client_get_default()
+ client.set_bool('/desktop/sugar/collaboration/publish_gadget', value)
+ return 0
diff --git a/shell/extensions/cpsection/network/view.py b/shell/extensions/cpsection/network/view.py
new file mode 100644
index 0000000..588daeb
--- /dev/null
+++ b/shell/extensions/cpsection/network/view.py
@@ -0,0 +1,250 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gobject
+from gettext import gettext as _
+
+from sugar.graphics import style
+
+from jarabe.controlpanel.sectionview import SectionView
+from jarabe.controlpanel.inlinealert import InlineAlert
+
+CLASS = 'Network'
+ICON = 'module-network'
+TITLE = _('Network')
+
+_APPLY_TIMEOUT = 3000
+
+class Network(SectionView):
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = model
+ self.restart_alerts = alerts
+ self._jabber_sid = 0
+ self._jabber_valid = True
+ self._radio_valid = True
+ self._jabber_change_handler = None
+ self._radio_change_handler = None
+ self._network_configuration_reset_handler = None
+
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+ self.set_spacing(style.DEFAULT_SPACING)
+ group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+ self._radio_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._jabber_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+
+ workspace = gtk.VBox()
+ workspace.show()
+
+ separator_wireless = gtk.HSeparator()
+ workspace.pack_start(separator_wireless, expand=False)
+ separator_wireless.show()
+
+ label_wireless = gtk.Label(_('Wireless'))
+ label_wireless.set_alignment(0, 0)
+ workspace.pack_start(label_wireless, expand=False)
+ label_wireless.show()
+ box_wireless = gtk.VBox()
+ box_wireless.set_border_width(style.DEFAULT_SPACING * 2)
+ box_wireless.set_spacing(style.DEFAULT_SPACING)
+
+ radio_info = gtk.Label(_("Turn off the wireless radio to save "
+ "battery life"))
+ radio_info.set_alignment(0, 0)
+ radio_info.set_line_wrap(True)
+ radio_info.show()
+ box_wireless.pack_start(radio_info, expand=False)
+
+ box_radio = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._button = gtk.CheckButton()
+ self._button.set_alignment(0, 0)
+ box_radio.pack_start(self._button, expand=False)
+ self._button.show()
+
+ label_radio = gtk.Label(_('Radio'))
+ label_radio.set_alignment(0, 0.5)
+ box_radio.pack_start(label_radio, expand=False)
+ label_radio.show()
+
+ box_wireless.pack_start(box_radio, expand=False)
+ box_radio.show()
+
+ self._radio_alert = InlineAlert()
+ self._radio_alert_box.pack_start(self._radio_alert, expand=False)
+ box_radio.pack_end(self._radio_alert_box, expand=False)
+ self._radio_alert_box.show()
+ if 'radio' in self.restart_alerts:
+ self._radio_alert.props.msg = self.restart_msg
+ self._radio_alert.show()
+
+ history_info = gtk.Label(_("Discard network history if you "
+ "have trouble connecting to the network"))
+ history_info.set_alignment(0, 0)
+ history_info.set_line_wrap(True)
+ history_info.show()
+ box_wireless.pack_start(history_info, expand=False)
+
+ box_clear_history = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._clear_history_button = gtk.Button()
+ self._clear_history_button.set_label(_('Discard network history'))
+ box_clear_history.pack_start(self._clear_history_button, expand=False)
+ self._clear_history_button.show()
+ box_wireless.pack_start(box_clear_history, expand=False)
+ box_clear_history.show()
+
+ workspace.pack_start(box_wireless, expand=False)
+ box_wireless.show()
+
+ separator_mesh = gtk.HSeparator()
+ workspace.pack_start(separator_mesh, False)
+ separator_mesh.show()
+
+ label_mesh = gtk.Label(_('Collaboration'))
+ label_mesh.set_alignment(0, 0)
+ workspace.pack_start(label_mesh, expand=False)
+ label_mesh.show()
+ box_mesh = gtk.VBox()
+ box_mesh.set_border_width(style.DEFAULT_SPACING * 2)
+ box_mesh.set_spacing(style.DEFAULT_SPACING)
+
+ server_info = gtk.Label(_("The server is the equivalent of what"
+ " room you are in; people on the same server"
+ " will be able to see each other, even when"
+ " they aren't on the same network."))
+ server_info.set_alignment(0, 0)
+ server_info.set_line_wrap(True)
+ box_mesh.pack_start(server_info, expand=False)
+ server_info.show()
+
+ box_server = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_server = gtk.Label(_('Server:'))
+ label_server.set_alignment(1, 0.5)
+ label_server.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ box_server.pack_start(label_server, expand=False)
+ group.add_widget(label_server)
+ label_server.show()
+ self._entry = gtk.Entry()
+ self._entry.set_alignment(0)
+ self._entry.modify_bg(gtk.STATE_INSENSITIVE,
+ style.COLOR_WHITE.get_gdk_color())
+ self._entry.modify_base(gtk.STATE_INSENSITIVE,
+ style.COLOR_WHITE.get_gdk_color())
+ self._entry.set_size_request(int(gtk.gdk.screen_width() / 3), -1)
+ box_server.pack_start(self._entry, expand=False)
+ self._entry.show()
+ box_mesh.pack_start(box_server, expand=False)
+ box_server.show()
+
+ self._jabber_alert = InlineAlert()
+ label_jabber_error = gtk.Label()
+ group.add_widget(label_jabber_error)
+ self._jabber_alert_box.pack_start(label_jabber_error, expand=False)
+ label_jabber_error.show()
+ self._jabber_alert_box.pack_start(self._jabber_alert, expand=False)
+ box_mesh.pack_end(self._jabber_alert_box, expand=False)
+ self._jabber_alert_box.show()
+ if 'jabber' in self.restart_alerts:
+ self._jabber_alert.props.msg = self.restart_msg
+ self._jabber_alert.show()
+
+ workspace.pack_start(box_mesh, expand=False)
+ box_mesh.show()
+
+ scrolled = gtk.ScrolledWindow()
+ scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ scrolled.add_with_viewport(workspace)
+ scrolled.show()
+ self.add(scrolled)
+
+ self.setup()
+
+ def setup(self):
+ self._entry.set_text(self._model.get_jabber())
+ try:
+ radio_state = self._model.get_radio()
+ except self._model.ReadError, detail:
+ self._radio_alert.props.msg = detail
+ self._radio_alert.show()
+ else:
+ self._button.set_active(radio_state)
+
+ self._jabber_valid = True
+ self._radio_valid = True
+ self.needs_restart = False
+ self._radio_change_handler = self._button.connect( \
+ 'toggled', self.__radio_toggled_cb)
+ self._jabber_change_handler = self._entry.connect( \
+ 'changed', self.__jabber_changed_cb)
+ self._network_configuration_reset_handler = \
+ self._clear_history_button.connect( \
+ 'clicked', self.__network_configuration_reset_cb)
+
+ def undo(self):
+ self._button.disconnect(self._radio_change_handler)
+ self._entry.disconnect(self._jabber_change_handler)
+ self._model.undo()
+ self._jabber_alert.hide()
+ self._radio_alert.hide()
+
+ def _validate(self):
+ if self._jabber_valid and self._radio_valid:
+ self.props.is_valid = True
+ else:
+ self.props.is_valid = False
+
+ def __radio_toggled_cb(self, widget, data=None):
+ radio_state = widget.get_active()
+ try:
+ self._model.set_radio(radio_state)
+ except self._model.ReadError, detail:
+ self._radio_alert.props.msg = detail
+ self._radio_valid = False
+ else:
+ self._radio_valid = True
+
+ self._validate()
+ return False
+
+ def __jabber_changed_cb(self, widget, data=None):
+ if self._jabber_sid:
+ gobject.source_remove(self._jabber_sid)
+ self._jabber_sid = gobject.timeout_add(_APPLY_TIMEOUT,
+ self.__jabber_timeout_cb, widget)
+
+ def __jabber_timeout_cb(self, widget):
+ self._jabber_sid = 0
+ if widget.get_text() == self._model.get_jabber:
+ return
+ try:
+ self._model.set_jabber(widget.get_text())
+ except self._model.ReadError, detail:
+ self._jabber_alert.props.msg = detail
+ self._jabber_valid = False
+ self._jabber_alert.show()
+ self.restart_alerts.append('jabber')
+ else:
+ self._jabber_valid = True
+ self._jabber_alert.hide()
+
+ self._validate()
+ return False
+
+ def __network_configuration_reset_cb(self, widget):
+ self._model.clear_networks()
diff --git a/shell/extensions/cpsection/power/Makefile.am b/shell/extensions/cpsection/power/Makefile.am
new file mode 100644
index 0000000..325260c
--- /dev/null
+++ b/shell/extensions/cpsection/power/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/power
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/power/__init__.py b/shell/extensions/cpsection/power/__init__.py
new file mode 100644
index 0000000..8b2e85f
--- /dev/null
+++ b/shell/extensions/cpsection/power/__init__.py
@@ -0,0 +1,23 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+CLASS = 'Power'
+ICON = 'module-power'
+TITLE = _('Power')
+KEYWORDS = ['automatic', 'extreme', 'power', 'suspend', 'battery']
+
diff --git a/shell/extensions/cpsection/power/model.py b/shell/extensions/cpsection/power/model.py
new file mode 100644
index 0000000..48d05de
--- /dev/null
+++ b/shell/extensions/cpsection/power/model.py
@@ -0,0 +1,116 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import os
+from gettext import gettext as _
+import logging
+
+import gconf
+import dbus
+
+OHM_SERVICE_NAME = 'org.freedesktop.ohm'
+OHM_SERVICE_PATH = '/org/freedesktop/ohm/Keystore'
+OHM_SERVICE_IFACE = 'org.freedesktop.ohm.Keystore'
+
+POWERD_FLAG_DIR = '/etc/powerd/flags'
+POWERD_INHIBIT_FLAG = '/etc/powerd/flags/inhibit-suspend'
+
+_logger = logging.getLogger('ControlPanel - Power')
+
+
+class ReadError(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+def using_powerd():
+ # directory exists if powerd running, and it's recent
+ # enough to be controllable.
+ return os.access(POWERD_FLAG_DIR, os.W_OK)
+
+def get_automatic_pm():
+ if using_powerd():
+ return not os.access(POWERD_INHIBIT_FLAG, os.R_OK)
+
+ # ohmd
+ client = gconf.client_get_default()
+ return client.get_bool('/desktop/sugar/power/automatic')
+
+def print_automatic_pm():
+ print ('off', 'on')[get_automatic_pm()]
+
+def set_automatic_pm(enabled):
+ """Automatic suspends on/off."""
+
+ if using_powerd():
+ # powerd
+ if enabled == 'off' or enabled == 0:
+ try:
+ fd = open(POWERD_INHIBIT_FLAG, 'w')
+ except IOError:
+ _logger.debug('File %s is not writeable' % POWERD_INHIBIT_FLAG)
+ else:
+ fd.close()
+ else:
+ os.unlink(POWERD_INHIBIT_FLAG)
+ return
+
+ # ohmd
+ bus = dbus.SystemBus()
+ proxy = bus.get_object(OHM_SERVICE_NAME, OHM_SERVICE_PATH)
+ keystore = dbus.Interface(proxy, OHM_SERVICE_IFACE)
+
+ if enabled == 'on' or enabled == 1:
+ keystore.SetKey("suspend.automatic_pm", 1)
+ enabled = True
+ elif enabled == 'off' or enabled == 0:
+ keystore.SetKey("suspend.automatic_pm", 0)
+ enabled = False
+ else:
+ raise ValueError(_("Error in automatic pm argument, use on/off."))
+
+ client = gconf.client_get_default()
+ client.set_bool('/desktop/sugar/power/automatic', enabled)
+ return
+
+def get_extreme_pm():
+ client = gconf.client_get_default()
+ return client.get_bool('/desktop/sugar/power/extreme')
+
+def print_extreme_pm():
+ print ('off', 'on')[get_extreme_pm()]
+
+def set_extreme_pm(enabled):
+ """Extreme power management on/off."""
+
+ bus = dbus.SystemBus()
+ proxy = bus.get_object(OHM_SERVICE_NAME, OHM_SERVICE_PATH)
+ keystore = dbus.Interface(proxy, OHM_SERVICE_IFACE)
+
+ if enabled == 'on' or enabled == 1:
+ keystore.SetKey("suspend.extreme_pm", 1)
+ enabled = True
+ elif enabled == 'off' or enabled == 0:
+ keystore.SetKey("suspend.extreme_pm", 0)
+ enabled = False
+ else:
+ raise ValueError(_("Error in extreme pm argument, use on/off."))
+
+ client = gconf.client_get_default()
+ client.set_bool('/desktop/sugar/power/extreme', enabled)
+ return 0
diff --git a/shell/extensions/cpsection/power/view.py b/shell/extensions/cpsection/power/view.py
new file mode 100644
index 0000000..8f1ed56
--- /dev/null
+++ b/shell/extensions/cpsection/power/view.py
@@ -0,0 +1,177 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+from gettext import gettext as _
+
+from sugar.graphics import style
+
+from jarabe.controlpanel.sectionview import SectionView
+from jarabe.controlpanel.inlinealert import InlineAlert
+
+class Power(SectionView):
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = model
+ self.restart_alerts = alerts
+ self._automatic_pm_valid = True
+ self._extreme_pm_valid = True
+ self._extreme_pm_change_handler = None
+ self._automatic_pm_change_handler = None
+
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+ self.set_spacing(style.DEFAULT_SPACING)
+ group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+ self._automatic_pm_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ self._extreme_pm_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+
+ separator_pm = gtk.HSeparator()
+ self.pack_start(separator_pm, expand=False)
+ separator_pm.show()
+
+ label_pm = gtk.Label(_('Power management'))
+ label_pm.set_alignment(0, 0)
+ self.pack_start(label_pm, expand=False)
+ label_pm.show()
+ box_pm = gtk.VBox()
+ box_pm.set_border_width(style.DEFAULT_SPACING * 2)
+ box_pm.set_spacing(style.DEFAULT_SPACING)
+
+ box_automatic_pm = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_automatic_pm = gtk.Label(
+ _('Automatic power management (increases battery life)'))
+ label_automatic_pm.set_alignment(0, 0.5)
+ self._automatic_button = gtk.CheckButton()
+ self._automatic_button.set_alignment(0, 0)
+ box_automatic_pm.pack_start(self._automatic_button, expand=False)
+ box_automatic_pm.pack_start(label_automatic_pm, expand=False)
+ self._automatic_button.show()
+ label_automatic_pm.show()
+ group.add_widget(label_automatic_pm)
+ box_pm.pack_start(box_automatic_pm, expand=False)
+ box_automatic_pm.show()
+
+ self._automatic_pm_alert = InlineAlert()
+ label_automatic_pm_error = gtk.Label()
+ group.add_widget(label_automatic_pm_error)
+ self._automatic_pm_alert_box.pack_start(label_automatic_pm_error,
+ expand=False)
+ label_automatic_pm_error.show()
+ self._automatic_pm_alert_box.pack_start(self._automatic_pm_alert,
+ expand=False)
+ box_pm.pack_end(self._automatic_pm_alert_box, expand=False)
+ self._automatic_pm_alert_box.show()
+ if 'automatic_pm' in self.restart_alerts:
+ self._automatic_pm_alert.props.msg = self.restart_msg
+ self._automatic_pm_alert.show()
+
+ box_extreme_pm = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ label_extreme_pm = gtk.Label(
+ _('Extreme power management (disables' \
+ 'wireless radio, increases battery life)'))
+ label_extreme_pm.set_alignment(0, 0.5)
+ self._extreme_button = gtk.CheckButton()
+ self._extreme_button.set_alignment(0, 0)
+ box_extreme_pm.pack_start(self._extreme_button, expand=False)
+ self._extreme_button.show()
+ box_extreme_pm.pack_start(label_extreme_pm, expand=False)
+ group.add_widget(label_extreme_pm)
+ label_extreme_pm.show()
+ box_pm.pack_start(box_extreme_pm, expand=False)
+ box_extreme_pm.show()
+
+ self._extreme_pm_alert = InlineAlert()
+ label_extreme_pm_error = gtk.Label()
+ group.add_widget(label_extreme_pm_error)
+ self._extreme_pm_alert_box.pack_start(label_extreme_pm_error,
+ expand=False)
+ label_extreme_pm_error.show()
+ self._extreme_pm_alert_box.pack_start(self._extreme_pm_alert,
+ expand=False)
+ box_pm.pack_end(self._extreme_pm_alert_box, expand=False)
+ self._extreme_pm_alert_box.show()
+ if 'extreme_pm' in self.restart_alerts:
+ self._extreme_pm_alert.props.msg = self.restart_msg
+ self._extreme_pm_alert.show()
+
+ self.pack_start(box_pm, expand=False)
+ box_pm.show()
+
+ self.setup()
+
+ def setup(self):
+ try:
+ automatic_state = self._model.get_automatic_pm()
+ extreme_state = self._model.get_extreme_pm()
+
+ except Exception, detail:
+ self._automatic_pm_alert.props.msg = detail
+ self._automatic_pm_alert.show()
+
+ self._extreme_pm_alert.props.msg = detail
+ self._extreme_pm_alert.show()
+ else:
+ self._automatic_button.set_active(automatic_state)
+ self._extreme_button.set_active(extreme_state)
+
+ self._extreme_pm_valid = True
+ self._automatic_pm_valid = True
+ self.needs_restart = False
+ self._automatic_pm_change_handler = self._automatic_button.connect( \
+ 'toggled', self.__automatic_pm_toggled_cb)
+ self._extreme_pm_change_handler = self._extreme_button.connect( \
+ 'toggled', self.__extreme_pm_toggled_cb)
+
+ def undo(self):
+ self._automatic_button.disconnect(self._automatic_pm_change_handler)
+ self._extreme_button.disconnect(self._extreme_pm_change_handler)
+ self._model.undo()
+ self._extreme_pm_alert.hide()
+ self._automatic_pm_alert.hide()
+
+ def _validate(self):
+ if self._extreme_pm_valid and self._automatic_pm_valid:
+ self.props.is_valid = True
+ else:
+ self.props.is_valid = False
+
+ def __automatic_pm_toggled_cb(self, widget, data=None):
+ state = widget.get_active()
+ try:
+ self._model.set_automatic_pm(state)
+ except Exception, detail:
+ print detail
+ self._automatic_pm_alert.props.msg = detail
+ else:
+ self._automatic_pm_valid = True
+
+ self._validate()
+ return False
+
+ def __extreme_pm_toggled_cb(self, widget, data=None):
+ state = widget.get_active()
+ try:
+ self._model.set_extreme_pm(state)
+ except Exception, detail:
+ print detail
+ self._extreme_pm_alert.props.msg = detail
+ else:
+ self._extreme_pm_valid = True
+
+ self._validate()
+ return False
diff --git a/shell/extensions/cpsection/updater/Makefile.am b/shell/extensions/cpsection/updater/Makefile.am
new file mode 100644
index 0000000..897dbf3
--- /dev/null
+++ b/shell/extensions/cpsection/updater/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = backends
+
+sugardir = $(pkgdatadir)/extensions/cpsection/updater
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/shell/extensions/cpsection/updater/__init__.py b/shell/extensions/cpsection/updater/__init__.py
new file mode 100644
index 0000000..6010615
--- /dev/null
+++ b/shell/extensions/cpsection/updater/__init__.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+
+CLASS = 'ActivityUpdater'
+ICON = 'module-updater'
+TITLE = _('Software update')
+KEYWORDS = ['software', 'activity', 'update']
diff --git a/shell/extensions/cpsection/updater/backends/Makefile.am b/shell/extensions/cpsection/updater/backends/Makefile.am
new file mode 100644
index 0000000..e280a07
--- /dev/null
+++ b/shell/extensions/cpsection/updater/backends/Makefile.am
@@ -0,0 +1,5 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/updater/backends
+
+sugar_PYTHON = \
+ aslo.py \
+ __init__.py
diff --git a/shell/extensions/cpsection/updater/backends/__init__.py b/shell/extensions/cpsection/updater/backends/__init__.py
new file mode 100644
index 0000000..0dd0174
--- /dev/null
+++ b/shell/extensions/cpsection/updater/backends/__init__.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+# Copyright (C) 2009, Sugar Labs
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
diff --git a/shell/extensions/cpsection/updater/backends/aslo.py b/shell/extensions/cpsection/updater/backends/aslo.py
new file mode 100644
index 0000000..5f257f9
--- /dev/null
+++ b/shell/extensions/cpsection/updater/backends/aslo.py
@@ -0,0 +1,161 @@
+#!/usr/bin/python
+# Copyright (C) 2009, Sugar Labs
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+'''Activity information microformat parser.
+
+Activity information is embedded in HTML/XHTML/XML pages using a
+Resource Description Framework (RDF) http://www.w3.org/RDF/ .
+
+An example::
+
+<?xml version="1.0" encoding="UTF-8"?>
+<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+<RDF:Description about="urn:mozilla:extension:bounce">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li resource="urn:mozilla:extension:bounce:7"/>
+ </RDF:Seq>
+ </em:updates>
+</RDF:Description>
+
+<RDF:Description about="urn:mozilla:extension:bounce:7">
+ <em:version>7</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{3ca105e0-2280-4897-99a0-c277d1b733d2}</em:id>
+ <em:minVersion>0.82</em:minVersion>
+ <em:maxVersion>0.84</em:maxVersion>
+ <em:updateLink>http://foo.xo</em:updateLink>
+ <em:updateSize>7</em:updateSize>
+ <em:updateHash>sha256:816a7c43b4f1ea4769c61c03ea4..</em:updateHash>
+ </RDF:Description>
+ </em:targetApplication>
+</RDF:Description></RDF:RDF>
+'''
+
+import logging
+from xml.etree.ElementTree import XML
+import traceback
+
+import gio
+
+from jarabe import config
+
+_FIND_DESCRIPTION = \
+ './/{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description'
+_FIND_VERSION = './/{http://www.mozilla.org/2004/em-rdf#}version'
+_FIND_LINK = './/{http://www.mozilla.org/2004/em-rdf#}updateLink'
+_FIND_SIZE = './/{http://www.mozilla.org/2004/em-rdf#}updateSize'
+
+_UPDATE_PATH = 'http://activities.sugarlabs.org/services/update-aslo.php'
+
+_fetcher = None
+
+
+class _UpdateFetcher(object):
+
+ _CHUNK_SIZE = 10240
+
+ def __init__(self, bundle, completion_cb):
+ # ASLO knows only about stable SP releases
+ major, minor = config.version.split('.')[0:2]
+ sp_version = '%s.%s' % (major, int(minor) + int(minor) % 2)
+
+ url = '%s?id=%s&appVersion=%s' % \
+ (_UPDATE_PATH, bundle.get_bundle_id(), sp_version)
+
+ logging.debug('Fetch %s', url)
+
+ self._completion_cb = completion_cb
+ self._file = gio.File(url)
+ self._stream = None
+ self._xml_data = ''
+ self._bundle = bundle
+
+ self._file.read_async(self.__file_read_async_cb)
+
+ def __file_read_async_cb(self, gfile, result):
+ try:
+ self._stream = self._file.read_finish(result)
+ except:
+ global _fetcher
+ _fetcher = None
+ self._completion_cb(None, None, None, None, traceback.format_exc())
+ return
+
+ self._stream.read_async(self._CHUNK_SIZE, self.__stream_read_async_cb)
+
+ def __stream_read_async_cb(self, stream, result):
+ xml_data = self._stream.read_finish(result)
+ if xml_data is None:
+ global _fetcher
+ _fetcher = None
+ self._completion_cb(self._bundle, None, None, None,
+ 'Error reading update information for %s from '
+ 'server.' % self._bundle.get_bundle_id())
+ return
+ elif not xml_data:
+ self._process_result()
+ else:
+ self._xml_data += xml_data
+ self._stream.read_async(self._CHUNK_SIZE,
+ self.__stream_read_async_cb)
+
+ def _process_result(self):
+ document = XML(self._xml_data)
+
+ if document.find(_FIND_DESCRIPTION) is None:
+ logging.debug('Bundle %s not available in the server for the '
+ 'version %s', self._bundle.get_bundle_id(), config.version)
+ version = None
+ link = None
+ size = None
+ else:
+ try:
+ version = int(document.find(_FIND_VERSION).text)
+ except ValueError:
+ logging.error(traceback.format_exc())
+ version = 0
+
+ link = document.find(_FIND_LINK).text
+
+ try:
+ size = long(document.find(_FIND_SIZE).text) * 1024
+ except ValueError:
+ logging.error(traceback.format_exc())
+ size = 0
+
+ global _fetcher
+ _fetcher = None
+ self._completion_cb(self._bundle, version, link, size, None)
+
+
+def fetch_update_info(bundle, completion_cb):
+ '''Queries the server for a newer version of the ActivityBundle.
+
+ completion_cb receives bundle, version, link, size and possibly an error
+ message:
+
+ def completion_cb(bundle, version, link, size, error_message):
+ '''
+ global _fetcher
+
+ if _fetcher is not None:
+ raise RuntimeError('Multiple simultaneous requests are not supported')
+
+ _fetcher = _UpdateFetcher(bundle, completion_cb)
diff --git a/shell/extensions/cpsection/updater/model.py b/shell/extensions/cpsection/updater/model.py
new file mode 100755
index 0000000..9845371
--- /dev/null
+++ b/shell/extensions/cpsection/updater/model.py
@@ -0,0 +1,346 @@
+# Copyright (C) 2009, Sugar Labs
+# Copyright (C) 2009, Tomeu Vizoso
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+'''Sugar bundle updater: model.
+
+This module implements the non-GUI portions of the bundle updater, including
+list of installed bundls, whether updates are needed, and the URL at which to
+find the bundle updated.
+'''
+
+import os
+import logging
+import tempfile
+from urlparse import urlparse
+import traceback
+
+import gobject
+import gio
+
+from sugar import env
+from sugar.datastore import datastore
+from sugar.bundle.activitybundle import ActivityBundle
+
+from jarabe.model import bundleregistry
+
+from backends import aslo
+
+
+class UpdateModel(gobject.GObject):
+ __gtype_name__ = 'SugarUpdateModel'
+
+ __gsignals__ = {
+ 'progress': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([int, str, float, int])),
+ }
+
+ ACTION_CHECKING = 0
+ ACTION_UPDATING = 1
+ ACTION_DOWNLOADING = 2
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self.updates = None
+ self._bundles_to_check = None
+ self._bundles_to_update = None
+ self._total_bundles_to_update = 0
+ self._downloader = None
+ self._cancelling = False
+
+ def check_updates(self):
+ self.updates = []
+ self._bundles_to_check = \
+ [bundle for bundle in bundleregistry.get_registry()]
+ self._check_next_update()
+
+ def _check_next_update(self):
+ total = len(bundleregistry.get_registry())
+ current = total - len(self._bundles_to_check)
+
+ bundle = self._bundles_to_check.pop()
+ self.emit('progress', UpdateModel.ACTION_CHECKING, bundle.get_name(),
+ current, total)
+
+ aslo.fetch_update_info(bundle, self.__check_completed_cb)
+
+ def __check_completed_cb(self, bundle, version, link, size, error_message):
+ if error_message is not None:
+ logging.error('Error getting update information from server:\n'
+ '%s' % error_message)
+
+ if version is not None and version > bundle.get_activity_version():
+ self.updates.append(BundleUpdate(bundle, version, link, size))
+
+ if self._cancelling:
+ self._cancel_checking()
+ elif self._bundles_to_check:
+ gobject.idle_add(self._check_next_update)
+ else:
+ total = len(bundleregistry.get_registry())
+ if bundle is None:
+ name = ''
+ else:
+ name = bundle.get_name()
+ self.emit('progress', UpdateModel.ACTION_CHECKING, name, total,
+ total)
+
+ def update(self, bundle_ids):
+ self._bundles_to_update = []
+ for bundle_update in self.updates:
+ if bundle_update.bundle.get_bundle_id() in bundle_ids:
+ self._bundles_to_update.append(bundle_update)
+
+ self._total_bundles_to_update = len(self._bundles_to_update)
+ self._download_next_update()
+
+ def _download_next_update(self):
+ if self._cancelling:
+ self._cancel_updating()
+ return
+
+ bundle_update = self._bundles_to_update.pop()
+
+ total = self._total_bundles_to_update * 2
+ current = total - len(self._bundles_to_update) * 2 - 2
+
+ self.emit('progress', UpdateModel.ACTION_DOWNLOADING,
+ bundle_update.bundle.get_name(), current, total)
+
+ self._downloader = _Downloader(bundle_update)
+ self._downloader.connect('progress', self.__downloader_progress_cb)
+ self._downloader.connect('error', self.__downloader_error_cb)
+
+ def __downloader_progress_cb(self, downloader, progress):
+ logging.debug('__downloader_progress_cb %r', progress)
+
+ if self._cancelling:
+ self._cancel_updating()
+ return
+
+ total = self._total_bundles_to_update * 2
+ current = total - len(self._bundles_to_update) * 2 - 2 + progress
+
+ self.emit('progress', UpdateModel.ACTION_DOWNLOADING,
+ self._downloader.bundle_update.bundle.get_name(),
+ current, total)
+
+ if progress == 1:
+ self._install_update(self._downloader.bundle_update,
+ self._downloader.get_local_file_path())
+ self._downloader = None
+
+ def __downloader_error_cb(self, downloader, error_message):
+ logging.error('Error downloading update:\n%s', error_message)
+
+ if self._cancelling:
+ self._cancel_updating()
+ return
+
+ total = self._total_bundles_to_update
+ current = total - len(self._bundles_to_update)
+ self.emit('progress', UpdateModel.ACTION_UPDATING, '', current, total)
+
+ if self._bundles_to_update:
+ # do it in idle so the UI has a chance to refresh
+ gobject.idle_add(self._download_next_update)
+
+ def _install_update(self, bundle_update, local_file_path):
+
+ total = self._total_bundles_to_update
+ current = total - len(self._bundles_to_update) - 0.5
+
+ self.emit('progress', UpdateModel.ACTION_UPDATING,
+ bundle_update.bundle.get_name(),
+ current, total)
+
+ # TODO: Should we first expand the zip async so we can provide progress
+ # and only then copy to the journal?
+ jobject = datastore.create()
+ try:
+ title = '%s-%s' % (bundle_update.bundle.get_name(),
+ bundle_update.version)
+ jobject.metadata['title'] = title
+ jobject.metadata['mime_type'] = ActivityBundle.MIME_TYPE
+ jobject.file_path = local_file_path
+ datastore.write(jobject, transfer_ownership=True)
+ finally:
+ jobject.destroy()
+
+ self.emit('progress', UpdateModel.ACTION_UPDATING,
+ bundle_update.bundle.get_name(),
+ current + 0.5, total)
+
+ if self._bundles_to_update:
+ # do it in idle so the UI has a chance to refresh
+ gobject.idle_add(self._download_next_update)
+
+ def cancel(self):
+ self._cancelling = True
+
+ def _cancel_checking(self):
+ logging.debug('UpdateModel._cancel_checking')
+ total = len(bundleregistry.get_registry())
+ current = total - len(self._bundles_to_check)
+ self.emit('progress', UpdateModel.ACTION_CHECKING, '', current, current)
+ self._bundles_to_check = None
+ self._cancelling = False
+
+ def _cancel_updating(self):
+ logging.debug('UpdateModel._cancel_updating')
+ current = self._total_bundles_to_update - len(self._bundles_to_update) - 1
+ self.emit('progress', UpdateModel.ACTION_UPDATING, '', current, current)
+
+ if self._downloader is not None:
+ self._downloader.cancel()
+ file_path = self._downloader.get_local_file_path()
+ if file_path is not None and os.path.exists(file_path):
+ os.unlink(file_path)
+ self._downloader = None
+
+ self._total_bundles_to_update = 0
+ self._bundles_to_update = None
+ self._cancelling = False
+
+class BundleUpdate(object):
+
+ def __init__(self, bundle, version, link, size):
+ self.bundle = bundle
+ self.version = version
+ self.link = link
+ self.size = size
+
+
+class _Downloader(gobject.GObject):
+ _CHUNK_SIZE = 10240 # 10K
+ __gsignals__ = {
+ 'progress': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([float])),
+ 'error': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ }
+
+ def __init__(self, bundle_update):
+ gobject.GObject.__init__(self)
+
+ self.bundle_update = bundle_update
+ self._input_stream = None
+ self._output_stream = None
+ self._pending_buffers = []
+ self._input_file = gio.File(bundle_update.link)
+ self._output_file = None
+ self._downloaded_size = 0
+ self._cancelling = False
+
+ self._input_file.read_async(self.__file_read_async_cb)
+
+ def cancel(self):
+ self._cancelling = True
+
+ def __file_read_async_cb(self, gfile, result):
+ if self._cancelling:
+ return
+
+ try:
+ self._input_stream = self._input_file.read_finish(result)
+ except:
+ self.emit('error', traceback.format_exc())
+ return
+
+ temp_file_path = self._get_temp_file_path(self.bundle_update.link)
+ self._output_file = gio.File(temp_file_path)
+ self._output_stream = self._output_file.create()
+
+ self._input_stream.read_async(self._CHUNK_SIZE, self.__read_async_cb,
+ gobject.PRIORITY_LOW)
+
+ def __read_async_cb(self, input_stream, result):
+ if self._cancelling:
+ return
+
+ data = input_stream.read_finish(result)
+
+ if data is None:
+ # TODO
+ pass
+ elif not data:
+ logging.debug('closing input stream')
+ self._input_stream.close()
+ self._check_if_finished_writing()
+ else:
+ self._pending_buffers.append(data)
+ self._input_stream.read_async(self._CHUNK_SIZE,
+ self.__read_async_cb,
+ gobject.PRIORITY_LOW)
+
+ self._write_next_buffer()
+
+ def __write_async_cb(self, output_stream, result, user_data):
+ if self._cancelling:
+ return
+
+ count = output_stream.write_finish(result)
+
+ self._downloaded_size += count
+ progress = self._downloaded_size / float(self.bundle_update.size)
+ self.emit('progress', progress)
+
+ self._check_if_finished_writing()
+
+ if self._pending_buffers:
+ self._write_next_buffer()
+
+ def _write_next_buffer(self):
+ if self._pending_buffers and not self._output_stream.has_pending():
+ data = self._pending_buffers.pop(0)
+ # TODO: we pass the buffer as user_data because of
+ # http://bugzilla.gnome.org/show_bug.cgi?id=564102
+ self._output_stream.write_async(data, self.__write_async_cb,
+ gobject.PRIORITY_LOW,
+ user_data=data)
+
+ def _get_temp_file_path(self, uri):
+ # TODO: Should we use the HTTP headers for the file name?
+ scheme_, netloc_, path, params_, query_, fragment_ = \
+ urlparse(uri)
+ path = os.path.basename(path)
+
+ if not os.path.exists(env.get_user_activities_path()):
+ os.makedirs(env.get_user_activities_path())
+
+ base_name, extension_ = os.path.splitext(path)
+ fd, file_path = tempfile.mkstemp(dir=env.get_user_activities_path(),
+ prefix=base_name, suffix='.xo')
+ os.close(fd)
+ os.unlink(file_path)
+
+ return file_path
+
+ def get_local_file_path(self):
+ return self._output_file.get_path()
+
+ def _check_if_finished_writing(self):
+ if not self._pending_buffers and \
+ not self._output_stream.has_pending() and \
+ self._input_stream.is_closed():
+
+ logging.debug('closing output stream')
+ self._output_stream.close()
+
+ self.emit('progress', 1.0)
diff --git a/shell/extensions/cpsection/updater/view.py b/shell/extensions/cpsection/updater/view.py
new file mode 100644
index 0000000..2164c0b
--- /dev/null
+++ b/shell/extensions/cpsection/updater/view.py
@@ -0,0 +1,391 @@
+# Copyright (C) 2008, One Laptop Per Child
+# Copyright (C) 2009, Tomeu Vizoso
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+from gettext import ngettext
+import locale
+import logging
+
+import gobject
+import gtk
+
+from sugar.graphics import style
+from sugar.graphics.icon import Icon, CellRendererIcon
+
+from jarabe.controlpanel.sectionview import SectionView
+
+from model import UpdateModel
+
+_DEBUG_VIEW_ALL = True
+
+
+class ActivityUpdater(SectionView):
+
+ def __init__(self, model, alerts):
+ SectionView.__init__(self)
+
+ self._model = UpdateModel()
+ self._model.connect('progress', self.__progress_cb)
+
+ self.set_spacing(style.DEFAULT_SPACING)
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+
+ self._top_label = gtk.Label()
+ self._top_label.set_line_wrap(True)
+ self._top_label.set_justify(gtk.JUSTIFY_LEFT)
+ self._top_label.props.xalign = 0
+ self.pack_start(self._top_label, expand=False)
+ self._top_label.show()
+
+ separator = gtk.HSeparator()
+ self.pack_start(separator, expand=False)
+ separator.show()
+
+ bottom_label = gtk.Label()
+ bottom_label.set_line_wrap(True)
+ bottom_label.set_justify(gtk.JUSTIFY_LEFT)
+ bottom_label.props.xalign = 0
+ bottom_label.set_markup(
+ _('Software updates correct errors, eliminate security ' \
+ 'vulnerabilities, and provide new features.'))
+ self.pack_start(bottom_label, expand=False)
+ bottom_label.show()
+
+ self._update_box = None
+ self._progress_pane = None
+
+ self._refresh()
+
+ def _switch_to_update_box(self):
+ if self._update_box in self.get_children():
+ return
+
+ if self._progress_pane in self.get_children():
+ self.remove(self._progress_pane)
+ self._progress_pane = None
+
+ if self._update_box is None:
+ self._update_box = UpdateBox(self._model)
+ self._update_box.refresh_button.connect('clicked',
+ self.__refresh_button_clicked_cb)
+ self._update_box.install_button.connect('clicked',
+ self.__install_button_clicked_cb)
+
+ self.pack_start(self._update_box, expand=True, fill=True)
+ self._update_box.show()
+
+ def _switch_to_progress_pane(self):
+ if self._progress_pane in self.get_children():
+ return
+
+ if self._update_box in self.get_children():
+ self.remove(self._update_box)
+ self._update_box = None
+
+ if self._progress_pane is None:
+ self._progress_pane = ProgressPane()
+ self._progress_pane.cancel_button.connect('clicked',
+ self.__cancel_button_clicked_cb)
+
+ self.pack_start(self._progress_pane, expand=True, fill=False)
+ self._progress_pane.show()
+
+ def _clear_center(self):
+ if self._progress_pane in self.get_children():
+ self.remove(self._progress_pane)
+ self._progress_pane = None
+
+ if self._update_box in self.get_children():
+ self.remove(self._update_box)
+ self._update_box = None
+
+ def __progress_cb(self, model, action, bundle_name, current, total):
+ if current == total and action == UpdateModel.ACTION_CHECKING:
+ self._finished_checking()
+ return
+ elif current == total:
+ self._finished_updating(int(current))
+ return
+
+ if action == UpdateModel.ACTION_CHECKING:
+ message = _('Checking %s...') % bundle_name
+ elif action == UpdateModel.ACTION_DOWNLOADING:
+ message = _('Downloading %s...') % bundle_name
+ elif action == UpdateModel.ACTION_UPDATING:
+ message = _('Updating %s...') % bundle_name
+
+ self._switch_to_progress_pane()
+ self._progress_pane.set_message(message)
+ self._progress_pane.set_progress(current / float(total))
+
+ def _finished_checking(self):
+ logging.debug('ActivityUpdater._finished_checking')
+ available_updates = len(self._model.updates)
+ if not available_updates:
+ top_message = _('Your software is up-to-date')
+ else:
+ top_message = ngettext('You can install %s update',
+ 'You can install %s updates',
+ available_updates)
+ top_message = top_message % available_updates
+ top_message = gobject.markup_escape_text(top_message)
+
+ self._top_label.set_markup('<big>%s</big>' % top_message)
+
+ if not available_updates:
+ self._clear_center()
+ else:
+ self._switch_to_update_box()
+ self._update_box.refresh()
+
+ def __refresh_button_clicked_cb(self, button):
+ self._refresh()
+
+ def _refresh(self):
+ top_message = _('Checking for updates...')
+ self._top_label.set_markup('<big>%s</big>' % top_message)
+ self._model.check_updates()
+
+ def __install_button_clicked_cb(self, button):
+ self._top_label.set_markup('<big>%s</big>' % _('Installing updates...'))
+ self._model.update(self._update_box.get_bundles_to_update())
+
+ def __cancel_button_clicked_cb(self, button):
+ self._model.cancel()
+
+ def _finished_updating(self, installed_updates):
+ logging.debug('ActivityUpdater._finished_updating')
+ top_message = ngettext('%s update was installed',
+ '%s updates were installed', installed_updates)
+ top_message = top_message % installed_updates
+ top_message = gobject.markup_escape_text(top_message)
+ self._top_label.set_markup('<big>%s</big>' % top_message)
+ self._clear_center()
+
+ def undo(self):
+ self._model.cancel()
+
+class ProgressPane(gtk.VBox):
+ '''Container which replaces the `ActivityPane` during refresh or
+ install.'''
+
+ def __init__(self):
+ gtk.VBox.__init__(self)
+ self.set_spacing(style.DEFAULT_PADDING)
+ self.set_border_width(style.DEFAULT_SPACING * 2)
+
+ self._progress = gtk.ProgressBar()
+ self.pack_start(self._progress)
+ self._progress.show()
+
+ self._label = gtk.Label()
+ self._label.set_line_wrap(True)
+ self._label.set_property('xalign', 0.5)
+ self._label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_BUTTON_GREY.get_gdk_color())
+ self.pack_start(self._label)
+ self._label.show()
+
+ alignment_box = gtk.Alignment(xalign=0.5, yalign=0.5)
+ self.pack_start(alignment_box)
+ alignment_box.show()
+
+ self.cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL)
+ alignment_box.add(self.cancel_button)
+ self.cancel_button.show()
+
+ def set_message(self, message):
+ self._label.set_text(message)
+
+ def set_progress(self, fraction):
+ self._progress.props.fraction = fraction
+
+
+class UpdateBox(gtk.VBox):
+
+ def __init__(self, model):
+ gtk.VBox.__init__(self)
+
+ self._model = model
+
+ self.set_spacing(style.DEFAULT_PADDING)
+
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.pack_start(scrolled_window)
+ scrolled_window.show()
+
+ self._update_list = UpdateList(model)
+ self._update_list.props.model.connect('row-changed',
+ self.__row_changed_cb)
+ scrolled_window.add(self._update_list)
+ self._update_list.show()
+
+ bottom_box = gtk.HBox()
+ bottom_box.set_spacing(style.DEFAULT_SPACING)
+ self.pack_start(bottom_box, expand=False)
+ bottom_box.show()
+
+ self._size_label = gtk.Label()
+ self._size_label.props.xalign = 0
+ self._size_label.set_justify(gtk.JUSTIFY_LEFT)
+ bottom_box.pack_start(self._size_label, expand=True)
+ self._size_label.show()
+
+ self.refresh_button = gtk.Button(stock=gtk.STOCK_REFRESH)
+ bottom_box.pack_start(self.refresh_button, expand=False)
+ self.refresh_button.show()
+
+ self.install_button = gtk.Button(_('Install selected'))
+ self.install_button.props.image = Icon(icon_name='emblem-downloads',
+ icon_size=gtk.ICON_SIZE_BUTTON)
+ bottom_box.pack_start(self.install_button, expand=False)
+ self.install_button.show()
+
+ self._update_total_size_label()
+
+ def refresh(self):
+ self._update_list.refresh()
+
+ def __row_changed_cb(self, list_model, path, iterator):
+ self._update_total_size_label()
+ self._update_install_button()
+
+ def _update_total_size_label(self):
+ total_size = 0
+ for row in self._update_list.props.model:
+ if row[UpdateListModel.SELECTED]:
+ total_size += row[UpdateListModel.SIZE]
+
+ markup = _('Download size: %s') % _format_size(total_size)
+ self._size_label.set_markup(markup)
+
+ def _update_install_button(self):
+ for row in self._update_list.props.model:
+ if row[UpdateListModel.SELECTED]:
+ self.install_button.props.sensitive = True
+ return
+ self.install_button.props.sensitive = False
+
+ def get_bundles_to_update(self):
+ bundles_to_update = []
+ for row in self._update_list.props.model:
+ if row[UpdateListModel.SELECTED]:
+ bundles_to_update.append(row[UpdateListModel.BUNDLE_ID])
+ return bundles_to_update
+
+
+class UpdateList(gtk.TreeView):
+
+ def __init__(self, model):
+ list_model = UpdateListModel(model)
+ gtk.TreeView.__init__(self, list_model)
+
+ self.set_reorderable(False)
+ self.set_enable_search(False)
+ self.set_headers_visible(False)
+
+ toggle_renderer = gtk.CellRendererToggle()
+ toggle_renderer.props.activatable = True
+ toggle_renderer.props.xpad = style.DEFAULT_PADDING
+ toggle_renderer.props.indicator_size = style.zoom(26)
+ toggle_renderer.connect('toggled', self.__toggled_cb)
+
+ toggle_column = gtk.TreeViewColumn()
+ toggle_column.pack_start(toggle_renderer)
+ toggle_column.add_attribute(toggle_renderer, 'active',
+ UpdateListModel.SELECTED)
+ self.append_column(toggle_column)
+
+ icon_renderer = CellRendererIcon(self)
+ icon_renderer.props.width = style.STANDARD_ICON_SIZE
+ icon_renderer.props.height = style.STANDARD_ICON_SIZE
+ icon_renderer.props.size = style.STANDARD_ICON_SIZE
+ icon_renderer.props.xpad = style.DEFAULT_PADDING
+ icon_renderer.props.ypad = style.DEFAULT_PADDING
+ icon_renderer.props.stroke_color = style.COLOR_TOOLBAR_GREY.get_svg()
+ icon_renderer.props.fill_color = style.COLOR_TRANSPARENT.get_svg()
+
+ icon_column = gtk.TreeViewColumn()
+ icon_column.pack_start(icon_renderer)
+ icon_column.add_attribute(icon_renderer, 'file-name',
+ UpdateListModel.ICON_FILE_NAME)
+ self.append_column(icon_column)
+
+ text_renderer = gtk.CellRendererText()
+
+ description_column = gtk.TreeViewColumn()
+ description_column.pack_start(text_renderer)
+ description_column.add_attribute(text_renderer, 'markup',
+ UpdateListModel.DESCRIPTION)
+ self.append_column(description_column)
+
+ def __toggled_cb(self, cell_renderer, path):
+ row = self.props.model[path]
+ row[UpdateListModel.SELECTED] = not row[UpdateListModel.SELECTED]
+
+ def refresh(self):
+ pass
+
+
+class UpdateListModel(gtk.ListStore):
+
+ BUNDLE_ID = 0
+ SELECTED = 1
+ ICON_FILE_NAME = 2
+ DESCRIPTION = 3
+ SIZE = 4
+
+ def __init__(self, model):
+ gtk.ListStore.__init__(self, str, bool, str, str, int)
+
+ for bundle_update in model.updates:
+ row = [None] * 5
+ row[self.BUNDLE_ID] = bundle_update.bundle.get_bundle_id()
+ row[self.SELECTED] = True
+ row[self.ICON_FILE_NAME] = bundle_update.bundle.get_icon()
+
+ details = _('From version %(current)d to %(new)s (Size: %(size)s)')
+ details = details % \
+ {'current': bundle_update.bundle.get_activity_version(),
+ 'new': bundle_update.version,
+ 'size': _format_size(bundle_update.size)}
+
+ row[self.DESCRIPTION] = '<b>%s</b>\n%s' % \
+ (bundle_update.bundle.get_name(), details)
+
+ row[self.SIZE] = bundle_update.size
+
+ self.append(row)
+
+
+def _format_size(size):
+ '''
+ Convert a given size in bytes to a nicer better readable unit
+ '''
+ if size == 0:
+ # TRANS: download size is 0
+ return _('None')
+ elif size < 1024:
+ # TRANS: download size of very small updates
+ return _('1 KB')
+ elif size < 1024 * 1024:
+ # TRANS: download size of small updates, e.g. '250 KB'
+ return locale.format(_('%.0f KB'), size / 1024.0)
+ else:
+ # TRANS: download size of updates, e.g. '2.3 MB'
+ return locale.format(_('%.1f MB'), size / 1024.0 / 1024)
diff --git a/shell/extensions/deviceicon/Makefile.am b/shell/extensions/deviceicon/Makefile.am
new file mode 100644
index 0000000..d46ddde
--- /dev/null
+++ b/shell/extensions/deviceicon/Makefile.am
@@ -0,0 +1,9 @@
+sugardir = $(pkgdatadir)/extensions/deviceicon
+
+sugar_PYTHON = \
+ __init__.py \
+ battery.py \
+ network.py \
+ speaker.py \
+ touchpad.py \
+ volume.py
diff --git a/shell/extensions/deviceicon/__init__.py b/shell/extensions/deviceicon/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shell/extensions/deviceicon/__init__.py
diff --git a/shell/extensions/deviceicon/battery.py b/shell/extensions/deviceicon/battery.py
new file mode 100644
index 0000000..edfcce4
--- /dev/null
+++ b/shell/extensions/deviceicon/battery.py
@@ -0,0 +1,251 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+import gconf
+
+import gobject
+import gtk
+import dbus
+
+from sugar.graphics import style
+from sugar.graphics.icon import get_icon_state
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.palette import Palette
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+
+_ICON_NAME = 'battery'
+
+_STATUS_CHARGING = 0
+_STATUS_DISCHARGING = 1
+_STATUS_FULLY_CHARGED = 2
+_STATUS_NOT_PRESENT = 3
+
+_LEVEL_PROP = 'battery.charge_level.percentage'
+_CHARGING_PROP = 'battery.rechargeable.is_charging'
+_DISCHARGING_PROP = 'battery.rechargeable.is_discharging'
+_PRESENT_PROP = 'battery.present'
+
+class DeviceView(TrayIcon):
+
+ FRAME_POSITION_RELATIVE = 102
+
+ def __init__(self, udi):
+ client = gconf.client_get_default()
+ self._color = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ TrayIcon.__init__(self, icon_name=_ICON_NAME, xo_color=self._color)
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+
+ self._model = DeviceModel(udi)
+ self.palette = BatteryPalette(_('My Battery'))
+ self.palette.set_group_id('frame')
+
+ self._model.connect('notify::level',
+ self._battery_status_changed_cb)
+ self._model.connect('notify::charging',
+ self._battery_status_changed_cb)
+ self._model.connect('notify::discharging',
+ self._battery_status_changed_cb)
+ self._model.connect('notify::present',
+ self._battery_status_changed_cb)
+ self._update_info()
+
+ def _update_info(self):
+ name = _ICON_NAME
+ current_level = self._model.props.level
+ xo_color = self._color
+ badge_name = None
+
+ if not self._model.props.present:
+ status = _STATUS_NOT_PRESENT
+ badge_name = None
+ xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(),
+ style.COLOR_WHITE.get_svg()))
+ elif self._model.props.charging:
+ status = _STATUS_CHARGING
+ name += '-charging'
+ xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(),
+ style.COLOR_WHITE.get_svg()))
+ elif self._model.props.discharging:
+ status = _STATUS_DISCHARGING
+ if current_level <= 15:
+ badge_name = 'emblem-warning'
+ else:
+ status = _STATUS_FULLY_CHARGED
+
+ self.icon.props.icon_name = get_icon_state(name, current_level, step=-5)
+ self.icon.props.xo_color = xo_color
+ self.icon.props.badge_name = badge_name
+
+ self.palette.set_level(current_level)
+ self.palette.set_status(status)
+
+ def _battery_status_changed_cb(self, pspec, param):
+ self._update_info()
+
+class BatteryPalette(Palette):
+
+ def __init__(self, primary_text):
+ Palette.__init__(self, primary_text)
+
+ self._level = 0
+ self._progress_bar = gtk.ProgressBar()
+ self._progress_bar.set_size_request(
+ style.zoom(style.GRID_CELL_SIZE * 4), -1)
+ self._progress_bar.show()
+ self._status_label = gtk.Label()
+ self._status_label.show()
+
+ vbox = gtk.VBox()
+ vbox.pack_start(self._progress_bar)
+ vbox.pack_start(self._status_label)
+ vbox.show()
+
+ self._progress_widget = vbox
+ self.set_content(self._progress_widget)
+
+ def set_level(self, percent):
+ self._level = percent
+ fraction = percent / 100.0
+ self._progress_bar.set_fraction(fraction)
+
+ def set_status(self, status):
+ current_level = self._level
+ secondary_text = ''
+ status_text = '%s%%' % current_level
+
+ progress_widget = self._progress_widget
+ if status == _STATUS_NOT_PRESENT:
+ secondary_text = _('Removed')
+ progress_widget = None
+ elif status == _STATUS_CHARGING:
+ secondary_text = _('Charging')
+ elif status == _STATUS_DISCHARGING:
+ if current_level <= 15:
+ secondary_text = _('Very little power remaining')
+ else:
+ #TODO: make this less of an wild/educated guess
+ minutes_remaining = int(current_level / 0.59)
+ remaining_hourpart = minutes_remaining / 60
+ remaining_minpart = minutes_remaining % 60
+ secondary_text = _('%(hour)d:%(min).2d remaining') % \
+ {'hour': remaining_hourpart, 'min': remaining_minpart}
+ else:
+ secondary_text = _('Charged')
+ self.set_content(progress_widget)
+
+ self.props.secondary_text = secondary_text
+ self._status_label.set_text(status_text)
+
+class DeviceModel(gobject.GObject):
+ __gproperties__ = {
+ 'level' : (int, None, None, 0, 100, 0,
+ gobject.PARAM_READABLE),
+ 'charging' : (bool, None, None, False,
+ gobject.PARAM_READABLE),
+ 'discharging' : (bool, None, None, False,
+ gobject.PARAM_READABLE),
+ 'present' : (bool, None, None, False,
+ gobject.PARAM_READABLE)
+ }
+
+ def __init__(self, udi):
+ gobject.GObject.__init__(self)
+
+ bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
+ proxy = bus.get_object('org.freedesktop.Hal', udi,
+ follow_name_owner_changes=True)
+ self._battery = dbus.Interface(proxy, 'org.freedesktop.Hal.Device')
+ bus.add_signal_receiver(self._battery_changed,
+ 'PropertyModified',
+ 'org.freedesktop.Hal.Device',
+ 'org.freedesktop.Hal',
+ udi)
+
+ self._level = self._get_level()
+ self._charging = self._get_charging()
+ self._discharging = self._get_discharging()
+ self._present = self._get_present()
+
+ def _get_level(self):
+ try:
+ return self._battery.GetProperty(_LEVEL_PROP)
+ except dbus.DBusException:
+ logging.error('Cannot access %s', _LEVEL_PROP)
+ return 0
+
+ def _get_charging(self):
+ try:
+ return self._battery.GetProperty(_CHARGING_PROP)
+ except dbus.DBusException:
+ logging.error('Cannot access %s', _CHARGING_PROP)
+ return False
+
+ def _get_discharging(self):
+ try:
+ return self._battery.GetProperty(_DISCHARGING_PROP)
+ except dbus.DBusException:
+ logging.error('Cannot access %s', _DISCHARGING_PROP)
+ return False
+
+ def _get_present(self):
+ try:
+ return self._battery.GetProperty(_PRESENT_PROP)
+ except dbus.DBusException:
+ logging.error('Cannot access %s', _PRESENT_PROP)
+ return False
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'level':
+ return self._level
+ if pspec.name == 'charging':
+ return self._charging
+ if pspec.name == 'discharging':
+ return self._discharging
+ if pspec.name == 'present':
+ return self._present
+
+ def get_type(self):
+ return 'battery'
+
+ def _battery_changed(self, num_changes, changes_list):
+ for change in changes_list:
+ if change[0] == _LEVEL_PROP:
+ self._level = self._get_level()
+ self.notify('level')
+ elif change[0] == _CHARGING_PROP:
+ self._charging = self._get_charging()
+ self.notify('charging')
+ elif change[0] == _DISCHARGING_PROP:
+ self._discharging = self._get_discharging()
+ self.notify('discharging')
+ elif change[0] == _PRESENT_PROP:
+ self._present = self._get_present()
+ self.notify('present')
+
+def setup(tray):
+ bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
+ proxy = bus.get_object('org.freedesktop.Hal',
+ '/org/freedesktop/Hal/Manager')
+ hal_manager = dbus.Interface(proxy, 'org.freedesktop.Hal.Manager')
+
+ for udi in hal_manager.FindDeviceByCapability('battery'):
+ tray.add_device(DeviceView(udi))
diff --git a/shell/extensions/deviceicon/network.py b/shell/extensions/deviceicon/network.py
new file mode 100644
index 0000000..6171f39
--- /dev/null
+++ b/shell/extensions/deviceicon/network.py
@@ -0,0 +1,1006 @@
+#
+# Copyright (C) 2008 One Laptop Per Child
+# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+# Copyright (C) 2010 Plan Ceibal, Daniel Castelo
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+import hashlib
+import socket
+import struct
+import re
+import datetime
+import time
+import gtk
+import glib
+import gobject
+import gconf
+import dbus
+
+from sugar.graphics.icon import get_icon_state
+from sugar.graphics import style
+from sugar.graphics.palette import Palette
+from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.icon import Icon
+from sugar.graphics import xocolor
+from sugar.util import unique_id
+from sugar import profile
+
+from jarabe.model import network
+from jarabe.model.network import Settings
+from jarabe.model.network import IP4Config
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+from jarabe.view.pulsingicon import PulsingIcon
+
+IP_ADDRESS_TEXT_TEMPLATE = _("IP address: %s")
+
+_NM_SERVICE = 'org.freedesktop.NetworkManager'
+_NM_IFACE = 'org.freedesktop.NetworkManager'
+_NM_PATH = '/org/freedesktop/NetworkManager'
+_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
+_NM_WIRED_IFACE = 'org.freedesktop.NetworkManager.Device.Wired'
+_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
+_NM_SERIAL_IFACE = 'org.freedesktop.NetworkManager.Device.Serial'
+_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
+_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
+_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
+
+_GSM_STATE_NOT_READY = 0
+_GSM_STATE_DISCONNECTED = 1
+_GSM_STATE_CONNECTING = 2
+_GSM_STATE_CONNECTED = 3
+_GSM_STATE_NEED_AUTH = 4
+
+
+class WirelessPalette(Palette):
+ __gtype_name__ = 'SugarWirelessPalette'
+
+ __gsignals__ = {
+ 'deactivate-connection' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([]))
+ }
+
+ def __init__(self, primary_text):
+ Palette.__init__(self, label=primary_text)
+
+ self._disconnect_item = None
+
+ self._channel_label = gtk.Label()
+ self._channel_label.props.xalign = 0.0
+ self._channel_label.show()
+
+ self._ip_address_label = gtk.Label()
+
+ self._info = gtk.VBox()
+
+ def _padded(child, xalign=0, yalign=0.5):
+ padder = gtk.Alignment(xalign=xalign, yalign=yalign,
+ xscale=1, yscale=0.33)
+ padder.set_padding(style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING)
+ padder.add(child)
+ return padder
+
+ self._info.pack_start(_padded(self._channel_label))
+ self._info.pack_start(_padded(self._ip_address_label))
+ self._info.show_all()
+
+ self._disconnect_item = MenuItem(_('Disconnect...'))
+ icon = Icon(icon_size=gtk.ICON_SIZE_MENU, icon_name='media-eject')
+ self._disconnect_item.set_image(icon)
+ self._disconnect_item.connect('activate', self.__disconnect_activate_cb)
+ self.menu.append(self._disconnect_item)
+
+ def set_connecting(self):
+ self.props.secondary_text = _('Connecting...')
+
+ def _set_connected(self, iaddress):
+ self.set_content(self._info)
+ self.props.secondary_text = _('Connected')
+ self._set_ip_address(iaddress)
+ self._disconnect_item.show()
+
+ def set_connected_with_frequency(self, frequency, iaddress):
+ self._set_connected(iaddress)
+ self._set_frequency(frequency)
+
+ def set_connected_with_channel(self, channel, iaddress):
+ self._set_connected(iaddress)
+ self._set_channel(channel)
+
+ def set_disconnected(self):
+ self.props.primary_text = ''
+ self.props.secondary_text = ''
+ self._disconnect_item.hide()
+ self.set_content(None)
+
+ def __disconnect_activate_cb(self, menuitem):
+ self.emit('deactivate-connection')
+
+ def _set_frequency(self, frequency):
+ channel = network.frequency_to_channel(frequency)
+ self._set_channel(channel)
+
+ def _set_channel(self, channel):
+ self._channel_label.set_text("%s: %d" % (_("Channel"), channel))
+
+ def _set_ip_address(self, ip_address):
+ if ip_address is not None:
+ ip_address_text = IP_ADDRESS_TEXT_TEMPLATE % \
+ socket.inet_ntoa(struct.pack('I', ip_address))
+ else:
+ ip_address_text = ""
+ self._ip_address_label.set_text(ip_address_text)
+
+
+class WiredPalette(Palette):
+ __gtype_name__ = 'SugarWiredPalette'
+
+ def __init__(self):
+ Palette.__init__(self, label=_('Wired Network'))
+
+ self._speed_label = gtk.Label()
+ self._speed_label.props.xalign = 0.0
+ self._speed_label.show()
+
+ self._ip_address_label = gtk.Label()
+
+ self._info = gtk.VBox()
+
+ def _padded(child, xalign=0, yalign=0.5):
+ padder = gtk.Alignment(xalign=xalign, yalign=yalign,
+ xscale=1, yscale=0.33)
+ padder.set_padding(style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING)
+ padder.add(child)
+ return padder
+
+ self._info.pack_start(_padded(self._speed_label))
+ self._info.pack_start(_padded(self._ip_address_label))
+ self._info.show_all()
+
+ self.set_content(self._info)
+ self.props.secondary_text = _('Connected')
+
+ def set_connected(self, speed, iaddress):
+ self._speed_label.set_text('%s: %d Mb/s' % (_('Speed'), speed))
+ self._set_ip_address(iaddress)
+
+ def _inet_ntoa(self, iaddress):
+ address = ['%s' % ((iaddress >> i) % 256) for i in [0, 8, 16, 24]]
+ return ".".join(address)
+
+ def _set_ip_address(self, ip_address):
+ if ip_address is not None:
+ ip_address_text = IP_ADDRESS_TEXT_TEMPLATE % \
+ socket.inet_ntoa(struct.pack('I', ip_address))
+ else:
+ ip_address_text = ""
+ self._ip_address_label.set_text(ip_address_text)
+
+class GsmPalette(Palette):
+ __gtype_name__ = 'SugarGsmPalette'
+
+ __gsignals__ = {
+ 'gsm-connect' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ 'gsm-disconnect' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ }
+
+ def __init__(self):
+
+ Palette.__init__(self, label=_('Wireless modem'))
+
+ self._current_state = None
+
+ self._toggle_state_item = gtk.MenuItem('')
+ self._toggle_state_item.connect('activate', self.__toggle_state_cb)
+ self.menu.append(self._toggle_state_item)
+ self._toggle_state_item.show()
+
+ self.set_state(_GSM_STATE_NOT_READY)
+
+ self.info_box = gtk.VBox()
+
+ self.data_label = gtk.Label()
+ self.data_label.props.xalign = 0.0
+ label_alignment = self._add_widget_with_padding(self.data_label)
+ self.info_box.pack_start(label_alignment)
+ self.data_label.show()
+ label_alignment.show()
+
+ self.connection_time_label = gtk.Label()
+ self.connection_time_label.props.xalign = 0.0
+ label_alignment = self._add_widget_with_padding( \
+ self.connection_time_label)
+ self.info_box.pack_start(label_alignment)
+ self.connection_time_label.show()
+ label_alignment.show()
+
+ self.info_box.show()
+ self.set_content(self.info_box)
+
+ def _add_widget_with_padding(self, child, xalign=0, yalign=0.5):
+ alignment = gtk.Alignment(xalign=xalign, yalign=yalign,
+ xscale=1, yscale=0.33)
+ alignment.set_padding(style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING,
+ style.DEFAULT_SPACING)
+ alignment.add(child)
+ return alignment
+
+ def set_state(self, state):
+ self._current_state = state
+ self._update_label_and_text()
+
+ def _update_label_and_text(self):
+ if self._current_state == _GSM_STATE_NOT_READY:
+ self._toggle_state_item.get_child().set_label('...')
+ self.props.secondary_text = _('Please wait...')
+
+ elif self._current_state == _GSM_STATE_DISCONNECTED:
+ self._toggle_state_item.get_child().set_label(_('Connect'))
+ self.props.secondary_text = _('Disconnected')
+
+ elif self._current_state == _GSM_STATE_CONNECTING:
+ self._toggle_state_item.get_child().set_label(_('Cancel'))
+ self.props.secondary_text = _('Connecting...')
+
+ elif self._current_state == _GSM_STATE_CONNECTED:
+ self._toggle_state_item.get_child().set_label(_('Disconnect'))
+ self.props.secondary_text = _('Connected')
+
+ elif self._current_state == _GSM_STATE_NEED_AUTH:
+ self._toggle_state_item.get_child().set_label(_('Sim requires Pin/Puk'))
+ self.props.secondary_text = _('Authentication Error')
+
+ else:
+ raise ValueError('Invalid GSM state while updating label and ' \
+ 'text, %s' % str(self._current_state))
+
+ def __toggle_state_cb(self, menuitem):
+ if self._current_state == _GSM_STATE_NOT_READY:
+ pass
+ elif self._current_state == _GSM_STATE_DISCONNECTED:
+ self.emit('gsm-connect')
+ elif self._current_state == _GSM_STATE_CONNECTING:
+ self.emit('gsm-disconnect')
+ elif self._current_state == _GSM_STATE_CONNECTED:
+ self.emit('gsm-disconnect')
+ elif self._current_state == _GSM_STATE_NEED_AUTH:
+ self.emit('gsm-disconnect')
+ else:
+ raise ValueError('Invalid GSM state while emitting signal, %s' % \
+ str(self._current_state))
+
+
+class WirelessDeviceView(ToolButton):
+
+ FRAME_POSITION_RELATIVE = 302
+
+ def __init__(self, device):
+ ToolButton.__init__(self)
+
+ self._bus = dbus.SystemBus()
+ self._device = device
+ self._device_props = None
+ self._flags = 0
+ self._name = ''
+ self._mode = network.NM_802_11_MODE_UNKNOWN
+ self._strength = 0
+ self._frequency = 0
+ self._device_state = None
+ self._color = None
+ self._active_ap_op = None
+
+ self._icon = PulsingIcon()
+ self._icon.props.icon_name = get_icon_state('network-wireless', 0)
+ self._inactive_color = xocolor.XoColor( \
+ "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self._icon.props.pulse_color = self._inactive_color
+ self._icon.props.base_color = self._inactive_color
+
+ self.set_icon_widget(self._icon)
+ self._icon.show()
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+ self._palette = WirelessPalette(self._name)
+ self._palette.connect('deactivate-connection',
+ self.__deactivate_connection_cb)
+ self.set_palette(self._palette)
+ self._palette.set_group_id('frame')
+
+ self._device_props = dbus.Interface(self._device,
+ 'org.freedesktop.DBus.Properties')
+ self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__get_device_props_reply_cb,
+ error_handler=self.__get_device_props_error_cb)
+
+ self._device_props.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
+ reply_handler=self.__get_active_ap_reply_cb,
+ error_handler=self.__get_active_ap_error_cb)
+
+ self._bus.add_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ def __get_device_props_reply_cb(self, properties):
+ if 'State' in properties:
+ self._device_state = properties['State']
+ self._update_state()
+
+ def __get_device_props_error_cb(self, err):
+ logging.error('Error getting the device properties: %s', err)
+
+ def __get_active_ap_reply_cb(self, active_ap_op):
+ if self._active_ap_op != active_ap_op:
+ if self._active_ap_op is not None:
+ self._bus.remove_signal_receiver(
+ self.__ap_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self._active_ap_op,
+ dbus_interface=_NM_ACCESSPOINT_IFACE)
+ if active_ap_op == '/':
+ self._active_ap_op = None
+ return
+ self._active_ap_op = active_ap_op
+ active_ap = self._bus.get_object(_NM_SERVICE, active_ap_op)
+ props = dbus.Interface(active_ap, 'org.freedesktop.DBus.Properties')
+
+ props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
+ reply_handler=self.__get_all_ap_props_reply_cb,
+ error_handler=self.__get_all_ap_props_error_cb)
+
+ self._bus.add_signal_receiver(self.__ap_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self._active_ap_op,
+ dbus_interface=_NM_ACCESSPOINT_IFACE)
+
+ def __get_active_ap_error_cb(self, err):
+ logging.error('Error getting the active access point: %s', err)
+
+ def __state_changed_cb(self, new_state, old_state, reason):
+ self._device_state = new_state
+ self._update_state()
+ self._device_props.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
+ reply_handler=self.__get_active_ap_reply_cb,
+ error_handler=self.__get_active_ap_error_cb)
+
+ def __ap_properties_changed_cb(self, properties):
+ self._update_properties(properties)
+
+ def _update_properties(self, properties):
+ if 'Mode' in properties:
+ self._mode = properties['Mode']
+ self._color = None
+ if 'Ssid' in properties:
+ self._name = properties['Ssid']
+ self._color = None
+ if 'Strength' in properties:
+ self._strength = properties['Strength']
+ if 'Flags' in properties:
+ self._flags = properties['Flags']
+ if 'Frequency' in properties:
+ self._frequency = properties['Frequency']
+
+ if self._color == None:
+ if self._mode == network.NM_802_11_MODE_ADHOC and \
+ network.is_sugar_adhoc_network(self._name):
+ self._color = profile.get_color()
+ else:
+ sha_hash = hashlib.sha1()
+ data = self._name + hex(self._flags)
+ sha_hash.update(data)
+ digest = hash(sha_hash.digest())
+ index = digest % len(xocolor.colors)
+
+ self._color = xocolor.XoColor('%s,%s' %
+ (xocolor.colors[index][0],
+ xocolor.colors[index][1]))
+ self._update()
+
+ def __get_all_ap_props_reply_cb(self, properties):
+ self._update_properties(properties)
+
+ def __get_all_ap_props_error_cb(self, err):
+ logging.error('Error getting the access point properties: %s', err)
+
+ def _update(self):
+ if self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
+ self._icon.props.badge_name = "emblem-locked"
+ else:
+ self._icon.props.badge_name = None
+
+ self._palette.props.primary_text = glib.markup_escape_text(self._name)
+
+ self._update_state()
+ self._update_color()
+
+ def _update_state(self):
+ if self._active_ap_op is not None:
+ state = self._device_state
+ else:
+ state = network.DEVICE_STATE_UNKNOWN
+
+ if self._mode != network.NM_802_11_MODE_ADHOC and \
+ network.is_sugar_adhoc_network(self._name) == False:
+ if state == network.DEVICE_STATE_ACTIVATED:
+ icon_name = '%s-connected' % 'network-wireless'
+ else:
+ icon_name = 'network-wireless'
+
+ icon_name = get_icon_state(icon_name, self._strength)
+ if icon_name:
+ self._icon.props.icon_name = icon_name
+ else:
+ channel = network.frequency_to_channel(self._frequency)
+ if state == network.DEVICE_STATE_ACTIVATED:
+ self._icon.props.icon_name = 'network-adhoc-%s-connected' \
+ % channel
+ else:
+ self._icon.props.icon_name = 'network-adhoc-%s' % channel
+ self._icon.props.base_color = profile.get_color()
+
+ if state == network.DEVICE_STATE_PREPARE or \
+ state == network.DEVICE_STATE_CONFIG or \
+ state == network.DEVICE_STATE_NEED_AUTH or \
+ state == network.DEVICE_STATE_IP_CONFIG:
+ self._palette.set_connecting()
+ self._icon.props.pulsing = True
+ elif state == network.DEVICE_STATE_ACTIVATED:
+ address = self._device_props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
+ self._palette.set_connected_with_frequency(self._frequency, address)
+ self._icon.props.pulsing = False
+ else:
+ self._icon.props.badge_name = None
+ self._icon.props.pulsing = False
+ self._icon.props.pulse_color = self._inactive_color
+ self._icon.props.base_color = self._inactive_color
+ self._palette.set_disconnected()
+
+ def _update_color(self):
+ self._icon.props.base_color = self._color
+
+ def __deactivate_connection_cb(self, palette, data=None):
+ if self._active_ap_op is not None:
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+ netmgr_props = dbus.Interface(
+ netmgr, 'org.freedesktop.DBus.Properties')
+ active_connections_o = netmgr_props.Get(_NM_IFACE,
+ 'ActiveConnections')
+
+ for conn_o in active_connections_o:
+ obj = self._bus.get_object(_NM_IFACE, conn_o)
+ props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+ if ap_op == self._active_ap_op:
+ netmgr.DeactivateConnection(conn_o)
+ break
+
+ def __activate_reply_cb(self, connection):
+ logging.debug('Network created: %s', connection)
+
+ def __activate_error_cb(self, err):
+ logging.debug('Failed to create network: %s', err)
+
+
+class OlpcMeshDeviceView(ToolButton):
+ _ICON_NAME = 'network-mesh'
+ FRAME_POSITION_RELATIVE = 302
+
+ def __init__(self, device, state):
+ ToolButton.__init__(self)
+
+ self._bus = dbus.SystemBus()
+ self._device = device
+ self._device_props = None
+ self._device_state = None
+ self._channel = 0
+
+ self._icon = PulsingIcon(icon_name=self._ICON_NAME)
+ self._inactive_color = xocolor.XoColor( \
+ "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self._icon.props.pulse_color = profile.get_color()
+ self._icon.props.base_color = self._inactive_color
+
+ self.set_icon_widget(self._icon)
+ self._icon.show()
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+ self._palette = WirelessPalette(_("Mesh Network"))
+ self._palette.connect('deactivate-connection',
+ self.__deactivate_connection)
+ self.set_palette(self._palette)
+ self._palette.set_group_id('frame')
+
+ self.update_state(state)
+
+ self._device_props = dbus.Interface(self._device,
+ 'org.freedesktop.DBus.Properties')
+ self._device_props.Get(_NM_OLPC_MESH_IFACE, 'ActiveChannel',
+ reply_handler=self.__get_active_channel_reply_cb,
+ error_handler=self.__get_active_channel_error_cb)
+
+ self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=device.object_path,
+ dbus_interface=_NM_OLPC_MESH_IFACE)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_OLPC_MESH_IFACE)
+
+ def __get_active_channel_reply_cb(self, channel):
+ self._channel = channel
+ self._update_text()
+
+ def __get_active_channel_error_cb(self, err):
+ logging.error('Error getting the active channel: %s', err)
+
+ def __state_changed_cb(self, new_state, old_state, reason):
+ self._device_state = new_state
+ self._update()
+
+ def __wireless_properties_changed_cb(self, properties):
+ if 'ActiveChannel' in properties:
+ self._channel = properties['ActiveChannel']
+ self._update_text()
+
+ def _update_text(self):
+ channel = str(self._channel)
+ text = _("Mesh Network %s") % glib.markup_escape_text(channel)
+ self._palette.props.primary_text = text
+
+ def _update(self):
+ state = self._device_state
+
+ if state in [network.DEVICE_STATE_PREPARE,
+ network.DEVICE_STATE_CONFIG,
+ network.DEVICE_STATE_NEED_AUTH,
+ network.DEVICE_STATE_IP_CONFIG]:
+ self._icon.props.base_color = self._inactive_color
+ self._icon.props.pulse_color = profile.get_color()
+ self._palette.set_connecting()
+ self._icon.props.pulsing = True
+ elif state == network.DEVICE_STATE_ACTIVATED:
+ address = self._device_props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
+ self._palette.set_connected_with_channel(self._channel, address)
+ self._icon.props.base_color = profile.get_color()
+ self._icon.props.pulsing = False
+ self._update_text()
+
+ def update_state(self, state):
+ self._device_state = state
+ self._update()
+
+ def __deactivate_connection(self, palette, data=None):
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+ netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties')
+ active_connections_o = netmgr_props.Get(_NM_IFACE,
+ 'ActiveConnections')
+
+ for conn_o in active_connections_o:
+ # The connection path for a mesh connection is the device itself.
+ obj = self._bus.get_object(_NM_IFACE, conn_o)
+ props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+
+ try:
+ obj = self._bus.get_object(_NM_IFACE, ap_op)
+ props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
+ if type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+ netmgr.DeactivateConnection(conn_o)
+ break
+ except dbus.exceptions.DBusException:
+ pass
+
+
+class WiredDeviceView(TrayIcon):
+
+ _ICON_NAME = 'network-wired'
+ FRAME_POSITION_RELATIVE = 301
+
+ def __init__(self, speed, address):
+ client = gconf.client_get_default()
+ color = xocolor.XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ TrayIcon.__init__(self, icon_name=self._ICON_NAME, xo_color=color)
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+ self._palette = WiredPalette()
+ self.set_palette(self._palette)
+ self._palette.set_group_id('frame')
+ self._palette.set_connected(speed, address)
+
+
+class GsmDeviceView(TrayIcon):
+
+ _ICON_NAME = 'network-gsm'
+ FRAME_POSITION_RELATIVE = 303
+
+ def __init__(self, device):
+ self._connection_time_handler = None
+ self._connection_timestamp = 0
+
+ client = gconf.client_get_default()
+ color = xocolor.XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ TrayIcon.__init__(self, icon_name=self._ICON_NAME, xo_color=color)
+
+ self._bus = dbus.SystemBus()
+ self._device = device
+ self._palette = None
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+
+ self._bus.add_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+ self._bus.add_signal_receiver(self.__ppp_stats_changed_cb,
+ signal_name='PppStats',
+ path=self._device.object_path,
+ dbus_interface=_NM_SERIAL_IFACE)
+ def create_palette(self):
+ palette = GsmPalette()
+
+ palette.set_group_id('frame')
+ palette.connect('gsm-connect', self.__gsm_connect_cb)
+ palette.connect('gsm-disconnect', self.__gsm_disconnect_cb)
+
+ self._palette = palette
+
+ props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties')
+ props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__current_state_check_cb,
+ error_handler=self.__current_state_check_error_cb)
+
+ return palette
+
+ def __gsm_connect_cb(self, palette, data=None):
+ connection = network.find_gsm_connection()
+ if connection is not None:
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+ netmgr.ActivateConnection(network.SETTINGS_SERVICE,
+ connection.path,
+ self._device.object_path,
+ '/',
+ reply_handler=self.__connect_cb,
+ error_handler=self.__connect_error_cb)
+
+ def __connect_cb(self, active_connection):
+ logging.debug('Connected successfully to gsm device, %s',
+ active_connection)
+
+ def __connect_error_cb(self, error):
+ raise RuntimeError('Error when connecting to gsm device, %s' % error)
+
+ def __gsm_disconnect_cb(self, palette, data=None):
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+ netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties')
+ active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
+
+ for conn_o in active_connections_o:
+ obj = self._bus.get_object(_NM_IFACE, conn_o)
+ props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ devices = props.Get(_NM_ACTIVE_CONN_IFACE, 'Devices')
+ if self._device.object_path in devices:
+ netmgr.DeactivateConnection(
+ conn_o,
+ reply_handler=self.__disconnect_cb,
+ error_handler=self.__disconnect_error_cb)
+ break
+
+ def __disconnect_cb(self):
+ logging.debug('Disconnected successfully gsm device')
+
+ def __disconnect_error_cb(self, error):
+ raise RuntimeError('Error when disconnecting gsm device, %s' % error)
+
+ def __state_changed_cb(self, new_state, old_state, reason):
+ logging.debug('State: %s to %s, reason %s', old_state, new_state, reason)
+ self._update_state(int(new_state))
+
+ def __current_state_check_cb(self, properties):
+ self._update_state(int(properties['State']))
+
+ def __current_state_check_error_cb(self, error):
+ raise RuntimeError('Error when checking gsm device state, %s' % error)
+
+ def _update_state(self, state):
+ gsm_state = None
+
+ if state is network.DEVICE_STATE_ACTIVATED:
+ gsm_state = _GSM_STATE_CONNECTED
+ connection = network.find_gsm_connection()
+ if connection is not None:
+ connection.set_connected()
+ self._connection_timestamp = time.time() - \
+ connection.get_settings().connection.timestamp
+ self._connection_time_handler = gobject.timeout_add_seconds( \
+ 1, self.__connection_timecount_cb)
+ self._update_stats(0, 0)
+ self._update_connection_time()
+ self._palette.info_box.show()
+
+ elif state is network.DEVICE_STATE_DISCONNECTED:
+ gsm_state = _GSM_STATE_DISCONNECTED
+ self._connection_timestamp = 0
+ if self._connection_time_handler is not None:
+ gobject.source_remove(self._connection_time_handler)
+ self._palette.info_box.hide()
+
+ elif state in [network.DEVICE_STATE_UNMANAGED,
+ network.DEVICE_STATE_UNAVAILABLE,
+ network.DEVICE_STATE_UNKNOWN]:
+ gsm_state = _GSM_STATE_NOT_READY
+
+ elif state in [network.DEVICE_STATE_PREPARE,
+ network.DEVICE_STATE_CONFIG,
+ network.DEVICE_STATE_IP_CONFIG]:
+ gsm_state = _GSM_STATE_CONNECTING
+
+ elif state in [network.DEVICE_STATE_NEED_AUTH]:
+ gsm_state = _GSM_STATE_NEED_AUTH
+
+ if self._palette is not None:
+ self._palette.set_state(gsm_state)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ def __ppp_stats_changed_cb(self, in_bytes, out_bytes):
+ self._update_stats(in_bytes, out_bytes)
+
+ def _update_stats(self, in_bytes, out_bytes):
+ in_KBytes = in_bytes / 1024
+ out_KBytes = out_bytes / 1024
+ text = _("Data sent %d KB / received %d KB") % (out_KBytes, in_KBytes)
+ self._palette.data_label.set_text(text)
+
+ def __connection_timecount_cb(self):
+ self._connection_timestamp = self._connection_timestamp + 1
+ self._update_connection_time()
+ return True
+
+ def _update_connection_time(self):
+ connection_time = datetime.datetime.fromtimestamp( \
+ self._connection_timestamp)
+ text = _("Connection time ") + connection_time.strftime('%H : %M : %S')
+ self._palette.connection_time_label.set_text(text)
+
+class WirelessDeviceObserver(object):
+ def __init__(self, device, tray):
+ self._device = device
+ self._device_view = None
+ self._tray = tray
+ self._device_view = WirelessDeviceView(self._device)
+ self._tray.add_device(self._device_view)
+
+ def disconnect(self):
+ self._device_view.disconnect()
+ self._tray.remove_device(self._device_view)
+ del self._device_view
+ self._device_view = None
+
+
+class MeshDeviceObserver(object):
+ def __init__(self, device, tray):
+ self._bus = dbus.SystemBus()
+ self._device = device
+ self._device_view = None
+ self._tray = tray
+
+ props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
+ props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__get_device_props_reply_cb,
+ error_handler=self.__get_device_props_error_cb)
+
+ self._bus.add_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ def _remove_device_view(self):
+ self._device_view.disconnect()
+ self._tray.remove_device(self._device_view)
+ self._device_view = None
+
+ def disconnect(self):
+ if self._device_view is not None:
+ self._remove_device_view()
+
+ self._bus.remove_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ def __get_device_props_reply_cb(self, properties):
+ if 'State' in properties:
+ self._update_state(properties['State'])
+
+ def __get_device_props_error_cb(self, err):
+ logging.error('Error getting the device properties: %s', err)
+
+ def __state_changed_cb(self, new_state, old_state, reason):
+ self._update_state(new_state)
+
+ def _update_state(self, state):
+ if state in (network.DEVICE_STATE_PREPARE, network.DEVICE_STATE_CONFIG,
+ network.DEVICE_STATE_NEED_AUTH,
+ network.DEVICE_STATE_IP_CONFIG,
+ network.DEVICE_STATE_ACTIVATED):
+ if self._device_view is not None:
+ self._device_view.update_state(state)
+ return
+
+ self._device_view = OlpcMeshDeviceView(self._device, state)
+ self._tray.add_device(self._device_view)
+ else:
+ if self._device_view is not None:
+ self._remove_device_view()
+
+
+class WiredDeviceObserver(object):
+ def __init__(self, device, tray):
+ self._bus = dbus.SystemBus()
+ self._device = device
+ self._device_state = None
+ self._device_view = None
+ self._tray = tray
+
+ props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties')
+ props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__get_device_props_reply_cb,
+ error_handler=self.__get_device_props_error_cb)
+
+ self._bus.add_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ def __get_device_props_reply_cb(self, properties):
+ if 'State' in properties:
+ self._update_state(properties['State'])
+
+ def __get_device_props_error_cb(self, err):
+ logging.error('Error getting the device properties: %s', err)
+
+ def __state_changed_cb(self, new_state, old_state, reason):
+ self._update_state(new_state)
+
+ def _update_state(self, state):
+ if state == network.DEVICE_STATE_ACTIVATED:
+ props = dbus.Interface(self._device,
+ 'org.freedesktop.DBus.Properties')
+ address = props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
+ speed = props.Get(_NM_WIRED_IFACE, 'Speed')
+ self._device_view = WiredDeviceView(speed, address)
+ self._tray.add_device(self._device_view)
+ else:
+ if self._device_view is not None:
+ self._tray.remove_device(self._device_view)
+ del self._device_view
+ self._device_view = None
+
+class GsmDeviceObserver(object):
+ def __init__(self, device, tray):
+ self._device = device
+ self._device_view = None
+ self._tray = tray
+
+ self._device_view = GsmDeviceView(device)
+ self._tray.add_device(self._device_view)
+
+ def disconnect(self):
+ self._device_view.disconnect()
+ self._tray.remove_device(self._device_view)
+ self._device_view = None
+
+class NetworkManagerObserver(object):
+ def __init__(self, tray):
+ self._bus = dbus.SystemBus()
+ self._devices = {}
+ self._netmgr = None
+ self._tray = tray
+
+ try:
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ self._netmgr = dbus.Interface(obj, _NM_IFACE)
+ except dbus.DBusException:
+ logging.error('%s service not available', _NM_SERVICE)
+ return
+
+ self._netmgr.GetDevices(reply_handler=self.__get_devices_reply_cb,
+ error_handler=self.__get_devices_error_cb)
+
+ self._bus.add_signal_receiver(self.__device_added_cb,
+ signal_name='DeviceAdded',
+ dbus_interface=_NM_IFACE)
+ self._bus.add_signal_receiver(self.__device_removed_cb,
+ signal_name='DeviceRemoved',
+ dbus_interface=_NM_IFACE)
+
+ def __get_devices_reply_cb(self, devices):
+ for device_op in devices:
+ self._check_device(device_op)
+
+ def __get_devices_error_cb(self, err):
+ logging.error('Failed to get devices: %s', err)
+
+ def _check_device(self, device_op):
+ nm_device = self._bus.get_object(_NM_SERVICE, device_op)
+ props = dbus.Interface(nm_device, 'org.freedesktop.DBus.Properties')
+
+ device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
+ if device_type == network.DEVICE_TYPE_802_3_ETHERNET:
+ device = WiredDeviceObserver(nm_device, self._tray)
+ self._devices[device_op] = device
+ elif device_type == network.DEVICE_TYPE_802_11_WIRELESS:
+ device = WirelessDeviceObserver(nm_device, self._tray)
+ self._devices[device_op] = device
+ elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+ device = MeshDeviceObserver(nm_device, self._tray)
+ self._devices[device_op] = device
+ elif device_type == network.DEVICE_TYPE_GSM_MODEM:
+ device = GsmDeviceObserver(nm_device, self._tray)
+ self._devices[device_op] = device
+
+ def __device_added_cb(self, device_op):
+ self._check_device(device_op)
+
+ def __device_removed_cb(self, device_op):
+ if device_op in self._devices:
+ device = self._devices[device_op]
+ device.disconnect()
+ del self._devices[device_op]
+
+def setup(tray):
+ device_observer = NetworkManagerObserver(tray)
diff --git a/shell/extensions/deviceicon/speaker.py b/shell/extensions/deviceicon/speaker.py
new file mode 100644
index 0000000..3a54464
--- /dev/null
+++ b/shell/extensions/deviceicon/speaker.py
@@ -0,0 +1,216 @@
+# Copyright (C) 2008 Martin Dengler
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import gconf
+
+import gobject
+import gtk
+
+from sugar.graphics import style
+from sugar.graphics.icon import get_icon_state, Icon
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.palette import Palette
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+from jarabe.model import sound
+
+_ICON_NAME = 'speaker'
+
+class DeviceView(TrayIcon):
+
+ FRAME_POSITION_RELATIVE = 103
+
+ def __init__(self):
+ client = gconf.client_get_default()
+ self._color = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ TrayIcon.__init__(self, icon_name=_ICON_NAME, xo_color=self._color)
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+
+ self._model = DeviceModel()
+ self._model.connect('notify::level', self.__speaker_status_changed_cb)
+ self._model.connect('notify::muted', self.__speaker_status_changed_cb)
+
+ self.connect('expose-event', self.__expose_event_cb)
+
+ self._icon_widget.connect('button-release-event',
+ self.__button_release_event_cb)
+
+ self._update_info()
+
+ def create_palette(self):
+ palette = SpeakerPalette(_('My Speakers'), model=self._model)
+ palette.set_group_id('frame')
+ return palette
+
+ def _update_info(self):
+ name = _ICON_NAME
+ current_level = self._model.props.level
+ xo_color = self._color
+
+ if self._model.props.muted:
+ name += '-muted'
+ xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(),
+ style.COLOR_WHITE.get_svg()))
+
+ self.icon.props.icon_name = get_icon_state(name, current_level, step=-1)
+ self.icon.props.xo_color = xo_color
+
+ def __button_release_event_cb(self, widget, event):
+ if event.button == 1:
+ self._model.props.muted = not self._model.props.muted
+ return True
+ else:
+ return False
+
+ def __expose_event_cb(self, *args):
+ self._update_info()
+
+ def __speaker_status_changed_cb(self, pspec_, param_):
+ self._update_info()
+
+class SpeakerPalette(Palette):
+
+ def __init__(self, primary_text, model):
+ Palette.__init__(self, label=primary_text)
+
+ self._model = model
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+ vbox.show()
+
+ vol_step = sound.VOLUME_STEP
+ self._adjustment = gtk.Adjustment(value=self._model.props.level,
+ lower=0,
+ upper=100 + vol_step,
+ step_incr=vol_step,
+ page_incr=vol_step,
+ page_size=vol_step)
+ self._hscale = gtk.HScale(self._adjustment)
+ self._hscale.set_digits(0)
+ self._hscale.set_draw_value(False)
+ vbox.add(self._hscale)
+ self._hscale.show()
+
+ self._mute_item = MenuItem('')
+ self._mute_icon = Icon(icon_size=gtk.ICON_SIZE_MENU)
+ self._mute_item.set_image(self._mute_icon)
+ self.menu.append(self._mute_item)
+ self._mute_item.show()
+
+ self._adjustment_handler_id = \
+ self._adjustment.connect('value_changed',
+ self.__adjustment_changed_cb)
+
+ self._model_notify_level_handler_id = \
+ self._model.connect('notify::level', self.__level_changed_cb)
+ self._model.connect('notify::muted', self.__muted_changed_cb)
+
+ self._mute_item.connect('activate', self.__mute_activate_cb)
+
+ self.connect('popup', self.__popup_cb)
+
+ def _update_muted(self):
+ if self._model.props.muted:
+ mute_item_text = _('Unmute')
+ mute_item_icon_name = 'dialog-ok'
+ else:
+ mute_item_text = _('Mute')
+ mute_item_icon_name = 'dialog-cancel'
+ self._mute_item.get_child().set_text(mute_item_text)
+ self._mute_icon.props.icon_name = mute_item_icon_name
+
+ def _update_level(self):
+ if self._adjustment.value != self._model.props.level:
+ self._adjustment.handler_block(self._adjustment_handler_id)
+ try:
+ self._adjustment.value = self._model.props.level
+ finally:
+ self._adjustment.handler_unblock(self._adjustment_handler_id)
+
+ def __adjustment_changed_cb(self, adj_):
+ self._model.handler_block(self._model_notify_level_handler_id)
+ try:
+ self._model.props.level = self._adjustment.value
+ finally:
+ self._model.handler_unblock(self._model_notify_level_handler_id)
+ self._model.props.muted = self._adjustment.value == 0
+
+ def __level_changed_cb(self, pspec_, param_):
+ self._update_level()
+
+ def __mute_activate_cb(self, menuitem_):
+ self._model.props.muted = not self._model.props.muted
+
+ def __muted_changed_cb(self, pspec_, param_):
+ self._update_muted()
+
+ def __popup_cb(self, palette_):
+ self._update_level()
+ self._update_muted()
+
+class DeviceModel(gobject.GObject):
+ __gproperties__ = {
+ 'level' : (int, None, None, 0, 100, 0, gobject.PARAM_READWRITE),
+ 'muted' : (bool, None, None, False, gobject.PARAM_READWRITE),
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ sound.muted_changed.connect(self.__muted_changed_cb)
+ sound.volume_changed.connect(self.__volume_changed_cb)
+
+ def __muted_changed_cb(self, **kwargs):
+ self.notify('muted')
+
+ def __volume_changed_cb(self, **kwargs):
+ self.notify('level')
+
+ def _get_level(self):
+ return sound.get_volume()
+
+ def _set_level(self, new_volume):
+ sound.set_volume(new_volume)
+
+ def _get_muted(self):
+ return sound.get_muted()
+
+ def _set_muted(self, mute):
+ sound.set_muted(mute)
+
+ def get_type(self):
+ return 'speaker'
+
+ def do_get_property(self, pspec):
+ if pspec.name == "level":
+ return self._get_level()
+ elif pspec.name == "muted":
+ return self._get_muted()
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == "level":
+ self._set_level(value)
+ elif pspec.name == "muted":
+ self._set_muted(value)
+
+def setup(tray):
+ tray.add_device(DeviceView())
diff --git a/shell/extensions/deviceicon/touchpad.py b/shell/extensions/deviceicon/touchpad.py
new file mode 100644
index 0000000..d9521c2
--- /dev/null
+++ b/shell/extensions/deviceicon/touchpad.py
@@ -0,0 +1,132 @@
+# Copyright (C) 2010, Walter Bender, Sugar Labs
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+from gettext import gettext as _
+import os
+
+import gtk
+import gconf
+
+import logging
+
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.palette import Palette
+from sugar.graphics import style
+
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+
+TOUCHPAD_MODE_CAPACITIVE = 'capacitive'
+TOUCHPAD_MODE_RESISTIVE = 'resistive'
+TOUCHPAD_MODES = [TOUCHPAD_MODE_CAPACITIVE, TOUCHPAD_MODE_RESISTIVE]
+STATUS_TEXT = {TOUCHPAD_MODE_CAPACITIVE: _('finger'),
+ TOUCHPAD_MODE_RESISTIVE: _('stylus')}
+STATUS_ICON = {TOUCHPAD_MODE_CAPACITIVE: 'touchpad-' + TOUCHPAD_MODE_CAPACITIVE,
+ TOUCHPAD_MODE_RESISTIVE: 'touchpad-' + TOUCHPAD_MODE_RESISTIVE}
+# NODE_PATH is used to communicate with the touchpad device.
+NODE_PATH = '/sys/devices/platform/i8042/serio1/ptmode'
+
+
+class DeviceView(TrayIcon):
+ """ Manage the touchpad mode from the device palette on the Frame. """
+
+ FRAME_POSITION_RELATIVE = 500
+
+ def __init__(self):
+ """ Create the icon that represents the touchpad. """
+ icon_name = STATUS_ICON[_read_touchpad_mode()]
+
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ TrayIcon.__init__(self, icon_name=icon_name, xo_color=color)
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ def create_palette(self):
+ """ Create a palette for this icon; called by the Sugar framework
+ when a palette needs to be displayed. """
+ self.palette = ResourcePalette(_('My touchpad'), self.icon)
+ self.palette.set_group_id('frame')
+ return self.palette
+
+ def __button_release_event_cb(self, widget, event):
+ """ Callback for button release event; used to invoke touchpad-mode
+ change. """
+ self.palette.toggle_mode()
+ return True
+
+
+class ResourcePalette(Palette):
+ """ Palette attached to the decive icon that represents the touchpas. """
+
+ def __init__(self, primary_text, icon):
+ """ Create the palette and initilize with current touchpad status. """
+ Palette.__init__(self, label=primary_text)
+
+ self._icon = icon
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+
+ self._status_text = gtk.Label()
+ vbox.pack_start(self._status_text, padding=style.DEFAULT_PADDING)
+ self._status_text.show()
+
+ vbox.show()
+
+ self._mode = _read_touchpad_mode()
+ self._update()
+
+ def _update(self):
+ """ Update the label and icon based on the current mode. """
+ self._status_text.set_label(STATUS_TEXT[self._mode])
+ self._icon.props.icon_name = STATUS_ICON[self._mode]
+
+ def toggle_mode(self):
+ """ Toggle the touchpad mode. """
+ self._mode = TOUCHPAD_MODES[1 - TOUCHPAD_MODES.index(self._mode)]
+ _write_touchpad_mode(self._mode)
+ self._update()
+
+
+def setup(tray):
+ """ Initialize the devic icon; called by the shell when initializing the
+ Frame. """
+ if os.path.exists(NODE_PATH):
+ tray.add_device(DeviceView())
+ _write_touchpad_mode(TOUCHPAD_MODE_CAPACITIVE)
+
+
+def _read_touchpad_mode():
+ """ Read the touchpad mode from the node path. """
+ node_file_handle = open(NODE_PATH, 'r')
+ text = node_file_handle.read()
+ node_file_handle.close()
+
+ return TOUCHPAD_MODES[int(text[0])]
+
+
+def _write_touchpad_mode(touchpad):
+ """ Write the touchpad mode to the node path. """
+ try:
+ node_file_handle = open(NODE_PATH, 'w')
+ except IOError, e:
+ logging.error('Error opening %s for writing: %s', NODE_PATH, e)
+ return
+ node_file_handle.write(str(TOUCHPAD_MODES.index(touchpad)))
+ node_file_handle.close()
diff --git a/shell/extensions/deviceicon/volume.py b/shell/extensions/deviceicon/volume.py
new file mode 100644
index 0000000..e7f62a2
--- /dev/null
+++ b/shell/extensions/deviceicon/volume.py
@@ -0,0 +1,121 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import gobject
+import gio
+import gtk
+import gconf
+
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.journal import journalactivity
+from jarabe.view.palettes import VolumePalette
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+
+_icons = {}
+
+class DeviceView(TrayIcon):
+
+ FRAME_POSITION_RELATIVE = 500
+
+ def __init__(self, mount):
+
+ self._mount = mount
+
+ icon_name = None
+ icon_theme = gtk.icon_theme_get_default()
+ for icon_name in self._mount.get_icon().props.names:
+ icon_info = icon_theme.lookup_icon(icon_name,
+ gtk.ICON_SIZE_LARGE_TOOLBAR, 0)
+ if icon_info is not None:
+ break
+
+ if icon_name is None:
+ icon_name = 'drive'
+
+ # TODO: retrieve the colors from the owner of the device
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ TrayIcon.__init__(self, icon_name=icon_name, xo_color=color)
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ def create_palette(self):
+ palette = VolumePalette(self._mount)
+ palette.set_group_id('frame')
+ return palette
+
+ def __button_release_event_cb(self, widget, event):
+ journal = journalactivity.get_journal()
+ journal.set_active_volume(self._mount)
+ journal.reveal()
+ return True
+
+def setup(tray):
+ gobject.idle_add(_setup_volumes, tray)
+
+def _setup_volumes(tray):
+ volume_monitor = gio.volume_monitor_get()
+
+ for volume in volume_monitor.get_volumes():
+ _mount(volume, tray)
+
+ for mount in volume_monitor.get_mounts():
+ _add_device(mount, tray)
+
+ volume_monitor.connect('volume-added', _volume_added_cb, tray)
+ volume_monitor.connect('mount-added', _mount_added_cb, tray)
+ volume_monitor.connect('mount-removed', _mount_removed_cb, tray)
+
+def _volume_added_cb(volume_monitor, volume, tray):
+ _mount(volume, tray)
+
+def _mount(volume, tray):
+ # Follow Nautilus behaviour here
+ # since it has the same issue with removable device
+ # and it would be good to not invent our own workflow
+ if hasattr(volume, 'should_automount') and not volume.should_automount():
+ return
+
+ #TODO: should be done by some other process, like gvfs-hal-volume-monitor
+ #TODO: use volume.should_automount() when it gets into pygtk
+ if volume.get_mount() is None and volume.can_mount():
+ #TODO: pass None as mount_operation, or better, SugarMountOperation
+ volume.mount(gtk.MountOperation(tray.get_toplevel()), _mount_cb)
+
+def _mount_cb(volume, result):
+ logging.debug('_mount_cb %r %r', volume, result)
+ volume.mount_finish(result)
+
+def _mount_added_cb(volume_monitor, mount, tray):
+ _add_device(mount, tray)
+
+def _mount_removed_cb(volume_monitor, mount, tray):
+ icon = _icons[mount]
+ tray.remove_device(icon)
+ del _icons[mount]
+
+def _add_device(mount, tray):
+ icon = DeviceView(mount)
+ _icons[mount] = icon
+ tray.add_device(icon)
+
diff --git a/shell/extensions/globalkey/Makefile.am b/shell/extensions/globalkey/Makefile.am
new file mode 100644
index 0000000..69afac2
--- /dev/null
+++ b/shell/extensions/globalkey/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/globalkey
+
+sugar_PYTHON = \
+ __init__.py \
+ screenshot.py \
+ viewsource.py
diff --git a/shell/extensions/globalkey/__init__.py b/shell/extensions/globalkey/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shell/extensions/globalkey/__init__.py
diff --git a/shell/extensions/globalkey/screenshot.py b/shell/extensions/globalkey/screenshot.py
new file mode 100644
index 0000000..8b4d4c2
--- /dev/null
+++ b/shell/extensions/globalkey/screenshot.py
@@ -0,0 +1,100 @@
+# Copyright (C) 2008 One Laptop Per Child
+# Copyright (C) 2009 Simon Schampijer, James Zaki
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import tempfile
+import time
+from gettext import gettext as _
+
+import gtk
+import gconf
+import dbus
+
+from sugar.datastore import datastore
+from sugar.graphics import style
+from sugar import env
+from jarabe.model import shell
+
+BOUND_KEYS = ['<alt>1', 'Print']
+
+def handle_key_press(key):
+ tmp_dir = os.path.join(env.get_profile_path(), 'data')
+ fd, file_path = tempfile.mkstemp(dir=tmp_dir)
+ os.close(fd)
+
+ window = gtk.gdk.get_default_root_window()
+ width, height = window.get_size()
+ x_orig, y_orig = window.get_origin()
+
+ screenshot = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, has_alpha=False,
+ bits_per_sample=8, width=width,
+ height=height)
+ screenshot.get_from_drawable(window, window.get_colormap(), x_orig,
+ y_orig, 0, 0, width, height)
+ screenshot.save(file_path, "png")
+
+ client = gconf.client_get_default()
+ color = client.get_string('/desktop/sugar/user/color')
+
+ content_title = None
+ shell_model = shell.get_model()
+ zoom_level = shell_model.zoom_level
+
+ # TRANS: Nouns of what a screenshot contains
+ if zoom_level == shell_model.ZOOM_MESH:
+ content_title = _('Mesh')
+ elif zoom_level == shell_model.ZOOM_GROUP:
+ content_title = _('Group')
+ elif zoom_level == shell_model.ZOOM_HOME:
+ content_title = _('Home')
+ elif zoom_level == shell_model.ZOOM_ACTIVITY:
+ activity = shell_model.get_active_activity()
+ if activity != None:
+ content_title = activity.get_title()
+ if content_title == None:
+ content_title = _('Activity')
+
+ if content_title is None:
+ title = _('Screenshot')
+ else:
+ title = _('Screenshot of \"%s\"') % content_title
+
+ jobject = datastore.create()
+ try:
+ jobject.metadata['title'] = title
+ jobject.metadata['keep'] = '0'
+ jobject.metadata['buddies'] = ''
+ jobject.metadata['preview'] = _get_preview_data(screenshot)
+ jobject.metadata['icon-color'] = color
+ jobject.metadata['mime_type'] = 'image/png'
+ jobject.file_path = file_path
+ datastore.write(jobject, transfer_ownership=True)
+ finally:
+ jobject.destroy()
+ del jobject
+
+def _get_preview_data(screenshot):
+ preview = screenshot.scale_simple(style.zoom(300), style.zoom(225),
+ gtk.gdk.INTERP_BILINEAR)
+ preview_data = []
+ def save_func(buf, data):
+ data.append(buf)
+
+ preview.save_to_callback(save_func, 'png', user_data=preview_data)
+
+ return dbus.ByteArray(''.join(preview_data))
+
diff --git a/shell/extensions/globalkey/viewsource.py b/shell/extensions/globalkey/viewsource.py
new file mode 100644
index 0000000..df3cd9e
--- /dev/null
+++ b/shell/extensions/globalkey/viewsource.py
@@ -0,0 +1,27 @@
+# Copyright (C) 2008 One Laptop Per Child
+# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from jarabe.view.viewsource import setup_view_source
+from jarabe.model import shell
+
+BOUND_KEYS = ['0xEC', '<alt><shift>v']
+
+def handle_key_press(key):
+ shell_model = shell.get_model()
+ activity = shell_model.get_active_activity()
+
+ setup_view_source(activity)
diff --git a/shell/po/ChangeLog b/shell/po/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shell/po/ChangeLog
diff --git a/shell/po/POTFILES.in b/shell/po/POTFILES.in
new file mode 100644
index 0000000..45a0549
--- /dev/null
+++ b/shell/po/POTFILES.in
@@ -0,0 +1,67 @@
+extensions/cpsection/aboutme/__init__.py
+extensions/cpsection/aboutme/model.py
+extensions/cpsection/aboutme/view.py
+extensions/cpsection/aboutcomputer/__init__.py
+extensions/cpsection/aboutcomputer/model.py
+extensions/cpsection/aboutcomputer/view.py
+extensions/cpsection/datetime/__init__.py
+extensions/cpsection/datetime/model.py
+extensions/cpsection/datetime/view.py
+extensions/cpsection/frame/__init__.py
+extensions/cpsection/frame/model.py
+extensions/cpsection/frame/view.py
+extensions/cpsection/keyboard/__init__.py
+extensions/cpsection/keyboard/view.py
+extensions/cpsection/language/__init__.py
+extensions/cpsection/language/model.py
+extensions/cpsection/language/view.py
+extensions/cpsection/modemconfiguration/__init__.py
+extensions/cpsection/modemconfiguration/view.py
+extensions/cpsection/network/__init__.py
+extensions/cpsection/network/model.py
+extensions/cpsection/network/view.py
+extensions/cpsection/power/__init__.py
+extensions/cpsection/power/model.py
+extensions/cpsection/power/view.py
+extensions/cpsection/updater/__init__.py
+extensions/cpsection/updater/view.py
+extensions/deviceicon/battery.py
+extensions/deviceicon/network.py
+extensions/deviceicon/speaker.py
+extensions/deviceicon/touchpad.py
+extensions/deviceicon/volume.py
+extensions/globalkey/screenshot.py
+data/sugar.schemas.in
+src/jarabe/controlpanel/cmd.py
+src/jarabe/controlpanel/gui.py
+src/jarabe/controlpanel/sectionview.py
+src/jarabe/controlpanel/toolbar.py
+src/jarabe/desktop/activitieslist.py
+src/jarabe/desktop/favoriteslayout.py
+src/jarabe/desktop/favoritesview.py
+src/jarabe/desktop/homebox.py
+src/jarabe/desktop/keydialog.py
+src/jarabe/desktop/meshbox.py
+src/jarabe/desktop/schoolserver.py
+src/jarabe/frame/activitiestray.py
+src/jarabe/frame/clipboardmenu.py
+src/jarabe/frame/clipboardobject.py
+src/jarabe/frame/devicestray.py
+src/jarabe/frame/zoomtoolbar.py
+src/jarabe/intro/window.py
+src/jarabe/journal/detailview.py
+src/jarabe/journal/expandedentry.py
+src/jarabe/journal/journalactivity.py
+src/jarabe/journal/journaltoolbox.py
+src/jarabe/journal/listview.py
+src/jarabe/journal/misc.py
+src/jarabe/journal/modalalert.py
+src/jarabe/journal/objectchooser.py
+src/jarabe/journal/palettes.py
+src/jarabe/journal/volumestoolbar.py
+src/jarabe/view/buddymenu.py
+src/jarabe/view/keyhandler.py
+src/jarabe/view/launcher.py
+src/jarabe/view/palettes.py
+src/jarabe/view/viewsource.py
+
diff --git a/shell/po/POTFILES.skip b/shell/po/POTFILES.skip
new file mode 100644
index 0000000..f199f9c
--- /dev/null
+++ b/shell/po/POTFILES.skip
@@ -0,0 +1 @@
+data/sugar.xml.in
diff --git a/shell/po/af.po b/shell/po/af.po
new file mode 100644
index 0000000..8d6c9e1
--- /dev/null
+++ b/shell/po/af.po
@@ -0,0 +1,522 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: 2008-06-20 18:58-0400\n"
+"Last-Translator: Morgan Collett <morgan.collett@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "Naam:"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "Kliek om die kleur the verander:"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr "Terug"
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "Klaar"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "Volgende"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "Verwyder vriend"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "Maak vriend"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "Nooi na %s"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "Verwyder"
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "Maak oop"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr "Hou"
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr "Maak oop met"
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Knipbord objek: %s."
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "Sleutel Tipe:"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "Geldigheidsverklaring Tipe:"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "Enkripsie Tipe:"
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:147
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "Koppel"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "Ontkoppel"
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "Ontkoppel..."
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr "Koppel..."
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr "Gekoppel"
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr "Ontkoppel..."
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr "Aangaan"
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr "Aansluit"
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr "Baie min krag oor"
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d oor"
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:40
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr "Ontkoppel"
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr "Kanaal"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "Buurt"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "Groep"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "Tuis"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "Aktiwiteit"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Om jou veranderings te gebruik moet jy sugar herbegin.\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "Kanselleer"
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr "Reg"
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr "Veranderings het herbegin nodig"
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr "Waarskuwing"
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr "Kanselleer veranderings"
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr "Later"
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr "Herbegin nou"
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr "Jy moet 'n naam inskryf."
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr "Vout in gespesifiseerde kleure."
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "Nie beskikbaar nie"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Jammer, ek praat nie '%s'."
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr "Jy moet 'n bediener inskryf."
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr "Vout in radio waarde: gebruik on/off."
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr "Omtrent My"
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr "Kliek om jou kleur te verander:"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr "Omtrent my XO"
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr "Identiteit"
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr "Seriële Nommer:"
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr "Sagteware"
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr "Bou:"
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr "Fermware:"
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr "Datem & Tyd"
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr "Tydsone"
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr "Raam"
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr "nooit"
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr "dadelik"
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr "%s sekondes"
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr "Aktiveerings Vertraging"
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr "Hoekie"
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr "Snykant"
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr "Taal"
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr "Netwerk"
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr "Draadloos"
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr "Radio:"
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr "Bediener:"
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr "Aan 'n Skool Mesh Portal gekoppel"
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr "Op soek na 'n Skool Mesh Portal..."
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr "Aan 'n XO Mesh Portal gekoppel"
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Op soek na 'n XO Mesh Portal..."
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr "Aan Eenvoudig Mesh gekoppel"
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr "Begin 'n Eenvoidige Mesh"
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr "Vreemde Mesh"
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr "Weier"
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr "Kontrole Paneel"
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr "Herbegin"
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr "Uitskakel"
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr "Registreer"
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr "Begin..."
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr "Stop"
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr "Begin"
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr "Wys inhoud"
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#~ msgid "Remove from ring"
+#~ msgstr "Verwyder van ring"
+
+#~ msgid "Add to ring"
+#~ msgstr "Bysit by ring"
diff --git a/shell/po/am.po b/shell/po/am.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/am.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/ar.po b/shell/po/ar.po
new file mode 100644
index 0000000..df5b323
--- /dev/null
+++ b/shell/po/ar.po
@@ -0,0 +1,1549 @@
+# translation of sugar.po to Arabic
+# Khaled Hosny <khaledhosny@eglug.org>, 2007, 2008, 2009.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+msgid ""
+msgstr ""
+"Project-Id-Version: sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-01-30 00:31-0500\n"
+"PO-Revision-Date: 2010-02-07 17:12+0200\n"
+"Last-Translator: Khaled Hosny <khaledhosny@eglug.org>\n"
+"Language-Team: Arabic <doc@arabeyes.org>\n"
+"Language: ar\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
+"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
+"X-Generator: Pootle 2.0.1\n"
+"Nplurals=6; Plural=N==0 ? 0: n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 "
+": n%100>=11 && n%100<=99 ? 4 : 5;\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "عنّي"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "يجب أن تُدخِل اسما."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "الحواف: اللون=%s التشبع=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "الحواف: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "الملء: اللون=%s التشبع=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "الملء: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "خطأ في مُغيّرات الألوان المحددة."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "خطأ في الألوان المحددة."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "الاسم:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "انقر لتغيير اللون:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "عن حاسوبي"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "غير مُتاح"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "المعرّف"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "الرقم التسلسلي:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "البرمجيات"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "البناء:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "سُكّر:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "البرمجيات المضمّنة:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "برمجية اللاسلكي المضمّنة:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "حقوق النشر والترخيص"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"سُكّر هي واجهة المستخدم الرسومية التي تنظر لها الآن. سُكّر برمجية حرّة تخضع "
+"لرخصة جنو للتأميم عامّة الأغراض، ويمكنك تعديلها و/أو توزيع نسخ منها وفق شروط "
+"معينة مذكورة هنا."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "الترخيص كاملا:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "التاريخ والوقت"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "عطل: المنطقة الزمنية لا وجود لها."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:33
+msgid "Timezone"
+msgstr "المنطقة الزمنية"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "الإطار"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "يجب أن تكون القيمة عددا صحيحا."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "أبدا"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "حالا"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s ثوان"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "تأخير التفعيل"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "الركن"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "الحافة"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "لوحة المفاتيح"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "طراز لوحة المفاتيح"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "زر تغيير التخطيط"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "تخطيط لوحة المفاتيح"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "اللغة"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "تعذّر الوصول إلى ‭~/.i18n‬. ستُنشأ إعدادات قياسية."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "تعذّر تحديد اللغة ذات الرمز=%s."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "آسف، لا أتحدث '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"أضف اللغات حسب الترتيب الذي تفضله. إذا لم تتوفر ترجمة ستؤخذ من التالية في "
+"القائمة."
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "الشبكة"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "الحالة مجهولة."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "خطأ في معامل الإذاعة المحدد، استخدم on/off."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "خطأ في المعامل المحدد، استخدم 0\\1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "اللاسلكي"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "عطل اللاسلكي لتوفير الطاقة"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "الإذاعة"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "تجاهل تأريخ الشبكة إن كنت تواجه مشاكل في الاتصال بالشبكة"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "تجاهل تأريخ الشبكة"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "التعاون"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"الخادوم مثله مثل الغرفة التي تجلس بها؛ الأشخاص على نفس الخادوم يرون بعضهم "
+"البعض، حتى لو لم يكونوا على نفس الشبكة."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "الخادوم:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "الطاقة"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "خطأ في معامل pm التلقائي، استخدم on/off."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "خطأ في معامل pm المتطرف، استخدم on/off."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "إدارة الطاقة"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "إدارة آلية للطاقة (تطيل من عمر البطارية)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr "إدارة قصوى للطاقة (تعطّل اللاسلكي وتطيل عمر البطارية)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "تحديث البرمجيات"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr "تحديث البرمجيات يُصلح الأعطال ويغلق الثغرات الأمنية ويوفر خصائص جديدة."
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "يلتمس %s..."
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "ينزّل %s..."
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "يحدّث %s..."
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "برمجيات محدّثة"
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "يمكنك تنزيل %s تحديث"
+msgstr[1] "يمكنك تنزيل تحديث واحد"
+msgstr[2] "يمكنك تنزيل تحديثين"
+msgstr[3] "يمكنك تنزيل %s تحديثات"
+msgstr[4] "يمكنك تنزيل %s تحديثا"
+msgstr[5] "يمكنك تنزيل %s تحديث"
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "يلتمس التحديثات..."
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "يُثبّت التحديثات..."
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "لم تُثبّت أي تحديثات"
+msgstr[1] "ثُبّت تحديث واحد"
+msgstr[2] "ثُبّت تحديثين"
+msgstr[3] "ثُبّتت %s تحديثات"
+msgstr[4] "ثُبّت %s تحديثا"
+msgstr[5] "ثُبّت %s تحديث"
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "ثبّت المختار"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "حجم التنزيل: %s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "من الإصدارة %(current)d إلى %(new)s (الحجم %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "صفر"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1 ك.بايت"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f ك.بايت"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f م.بايت"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "بطاريتي"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "أُزيل"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "يشحن"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "بقي القليل جدا من الطاقة"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "باقي %(hour)d:%(min).2d"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "مشحون"
+
+#: ../extensions/deviceicon/network.py:47
+#, python-format
+msgid "IP address: %s"
+msgstr "رقم (عنوان) الإنترنت: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:108
+msgid "Disconnect..."
+msgstr "افصِل..."
+
+#: ../extensions/deviceicon/network.py:113
+msgid "Create new wireless network"
+msgstr "أنشئ شبكة لاسلكية جديدة"
+
+#: ../extensions/deviceicon/network.py:119
+#: ../extensions/deviceicon/network.py:250
+#: ../src/jarabe/desktop/meshbox.py:248 ../src/jarabe/desktop/meshbox.py:537
+msgid "Connecting..."
+msgstr "يتصّل..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:123
+#: ../extensions/deviceicon/network.py:195
+#: ../extensions/deviceicon/network.py:254
+#: ../src/jarabe/desktop/meshbox.py:254 ../src/jarabe/desktop/meshbox.py:543
+msgid "Connected"
+msgstr "مُتّصل"
+
+#: ../extensions/deviceicon/network.py:155
+msgid "Channel"
+msgstr "قناة"
+
+#: ../extensions/deviceicon/network.py:170
+msgid "Wired Network"
+msgstr "شبكة سلكية"
+
+#: ../extensions/deviceicon/network.py:198
+msgid "Speed"
+msgstr "السرعة"
+
+#: ../extensions/deviceicon/network.py:224
+msgid "Wireless modem"
+msgstr "مودم لاسلكي"
+
+#: ../extensions/deviceicon/network.py:242
+msgid "Please wait..."
+msgstr "انتظر من فضلك..."
+
+#: ../extensions/deviceicon/network.py:245
+#: ../src/jarabe/desktop/meshbox.py:164 ../src/jarabe/desktop/meshbox.py:494
+msgid "Connect"
+msgstr "اتصل"
+
+#: ../extensions/deviceicon/network.py:246
+msgid "Disconnected"
+msgstr "مفصول"
+
+#: ../extensions/deviceicon/network.py:249
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "ألغِ"
+
+#: ../extensions/deviceicon/network.py:253
+#: ../src/jarabe/desktop/meshbox.py:168
+msgid "Disconnect"
+msgstr "اقطع الاتصال"
+
+#: ../extensions/deviceicon/network.py:496
+#, python-format
+msgid "%s's network"
+msgstr "شبكة %s"
+
+#: ../extensions/deviceicon/network.py:562
+#: ../extensions/deviceicon/network.py:621
+msgid "Mesh Network"
+msgstr "شبكة عُروِيّة"
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "سماعاتي"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "افتح"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "أصمِت"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "الشبكة العروية"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "المجموعة"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "المنزل"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "النشاط"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "لقطة شاشة"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "لقطة من \"%s\""
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr ""
+"استخدم \"disabled\" (معطل) للسؤال عن الكنية عند البدء، أو \"system\" (النظام) "
+"لاستخدام اسم الولوج إلى حساب النظام."
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Backup URL"
+msgstr "مسار النسخ الاحتياطي"
+
+#: ../data/sugar.schemas.in.h:3
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"لون الأيقونة المستخدم في أنحاء سطح المكتب. يركب من لون الحواف ولون الملء "
+"بنسق ألون rbg. مثال: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Corner Delay"
+msgstr "تأخير الركن"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Default font face"
+msgstr "الخط المبدئي"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font size"
+msgstr "حجم الخط المبدئي"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default nick"
+msgstr "الكنية المبدئية"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Delay for the activation of the frame using the corners."
+msgstr "تأخير تنشيط الإطار باستخدام الأركان."
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the edges."
+msgstr "تأخير تنشيط الإطار باستخدام الحواف."
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Edge Delay"
+msgstr "تأخير الحافة"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Favorites Layout"
+msgstr "المنظور المفضل"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Favorites resume mode"
+msgstr "طور الاستكمال المفضل"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Font face that is used throughout the desktop."
+msgstr "الخط المستَخدم في أرجاء سطح المكتب."
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Font size that is used throughout the desktop."
+msgstr "حجم الخط المستَخدم في أرجاء سطح المكتب."
+
+#: ../data/sugar.schemas.in.h:15
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr "إذا ضبطت \"صحيح\" فستتيح سكّر البحث عنا في خادوم جابِر."
+
+#: ../data/sugar.schemas.in.h:16
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "إذا ضبطت \"صحيح\" فستظهر سكّر خيار \"اخرج\"."
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Jabber Server"
+msgstr "خادوم جابِر"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Keyboard layouts"
+msgstr "تخطيطات لوحة المفاتيح"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Keyboard model"
+msgstr "طراز لوحة المفاتيح"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Keyboard options"
+msgstr "خيارات لوحة المفاتيح"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Layout of the favorites view."
+msgstr "تنظيم المنظور المفضل."
+
+#: ../data/sugar.schemas.in.h:22
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr "قائمة بتخطيطات لوحة المفاتيح، كل على الشكل ‪layout(variant)‬"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "List of keyboard options."
+msgstr "قائمة بخيارات لوحة المفاتيح."
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Power Automatic"
+msgstr "الطاقة تلقائية"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Power Automatic."
+msgstr "الطاقة تلقائية."
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Power Extreme"
+msgstr "الطاقة متشددة"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Power Extreme."
+msgstr "الطاقة متشددة."
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Publish to Gadget"
+msgstr "انشر في Gadget"
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Setting for muting the sound device."
+msgstr "إعداد لكتم صوت الجهاز."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Show Log out"
+msgstr "أظهر الخروج"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Sound Muted"
+msgstr "الصوت مُصمَت"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "The keyboard model to be used"
+msgstr "طراز لوحة المفاتيح الذي سيستخدم"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Timezone setting for the system."
+msgstr "المنطقة الزمنية للنظام."
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Url of the jabber server to use."
+msgstr "مسار خادوم جابِر الذي سيستخدم."
+
+#: ../data/sugar.schemas.in.h:36
+msgid "Url where the backup is saved to."
+msgstr "مسار مكان الحفظ الاحتياطي."
+
+#: ../data/sugar.schemas.in.h:37
+msgid "User Color"
+msgstr "لون المستخدم"
+
+#: ../data/sugar.schemas.in.h:38
+msgid "User Name"
+msgstr "اسم المستخدم"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "User name that is used throughout the desktop."
+msgstr "الاسم المستَخدم في أرجاء سطح المكتب."
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Volume Level"
+msgstr "مستوى الصوت"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Volume level for the sound device."
+msgstr "مستوى شدة الصوت."
+
+#: ../data/sugar.schemas.in.h:42
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr "في وضع الاستكمال، النقر على أيقونة مفضلة سيستكمل آخر مدخلة لهذا النشاط."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr "لوحة تحكم سكر: تحذير، وُجد أكثر من خيار بنفس الاسم: %s الوحدة: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "لوحة تحكم سكر: key=%s ليس متاحا كخيار"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "لوحة تحكم سكر: %s"
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"الاستخدام: لوحة تحكم سكر [ خيار ] مفتاح [ معاملات ... ]\n"
+"لوحة تحكم لبيئة «سُكّر».\n"
+"الخيارات: \n"
+"-hاعرض رسالة المساعدة هذه \n"
+"-lاسرد كل الخيارات المتاحة \n"
+"-h keyاعرض معلومات عن هذا المفتاح \n"
+"-g key اعرض القيمة الحالية للمفتاح \n"
+"-s keyاضبط قيمة المفتاح \n"
+"-c keyامسح القيمة الحالية للمفتاح \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "تحتاج لإعادة تشغيل «سُكّر» لتُطبق التغييرات.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "تحذير"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "تتطلب التغييرات إعادة التشغيل"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "ألغِ التغييرات"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "لاحقا"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "أعِد التشغيل الآن"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "تمّ"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "حسنا"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "الإصدارة %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "أكّد المسح"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "أكّد المسح: أتريد مسح %s نهائيا؟"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "احفظ"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:105
+msgid "Erase"
+msgstr "امسح"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "احذف المفضلة"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "اصنع مفضلة"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "حُر"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "حلقة"
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "حلزون"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "صندوق"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "مثلث"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "فشل التسجيل"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "نجح التسجيل"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "الآن، أنت مسجّل في خادوم مدرستك."
+
+#: ../src/jarabe/desktop/favoritesview.py:630
+msgid "Register"
+msgstr "سجّل"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "تحديث البرمجيات"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "حدّث نشاطاتك لتضمن التوافقية مع البرمجيات الجديدة"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "التمس الآن"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "منظور القائمة"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "‪<Ctrl>‬2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "المنظور المفضل"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "‪<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "نوع المفتاح:"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "نوع الاستيثاق:"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "‏WPA و WPA2 شخصي"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "أمن اللاسلكي:"
+
+#: ../src/jarabe/desktop/meshbox.py:492
+#, python-format
+msgid "Mesh Network %d"
+msgstr "شبكة عُروِيّة %d"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:629
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:65 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "استكمل"
+
+#: ../src/jarabe/desktop/meshbox.py:634
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "التحق"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "تعذّر الاتصال بالخادوم."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "لم يستطع الخادوم إكمال الطلب."
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "ارفض"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%d بايت"
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%d ك.بايت"
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%d م.بايت"
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "‏%s من %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "نقل من %r"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "اقبل"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "‏%s ‏(%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr "ارفض"
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "نقل إلى %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "أزل"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "افتح"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "افتح باستخدام"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "قصاصة %s"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "الجِوَار"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "انقر لتغيير اللون:"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "السابق"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "التالي"
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:59
+msgid "Untitled"
+msgstr "بدون عنوان"
+
+#: ../src/jarabe/journal/expandedentry.py:243
+msgid "No preview"
+msgstr "لا معاينة"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Kind: %s"
+msgstr "النوع: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+msgid "Unknown"
+msgstr "مجهول"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Date: %s"
+msgstr "التاريخ: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Size: %s"
+msgstr "الحجم: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:286 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "لا تاريخ"
+
+#: ../src/jarabe/journal/expandedentry.py:293
+msgid "Participants:"
+msgstr "المشاركون:"
+
+#: ../src/jarabe/journal/expandedentry.py:316
+msgid "Description:"
+msgstr "الوصف:"
+
+#: ../src/jarabe/journal/expandedentry.py:341
+msgid "Tags:"
+msgstr "الوُسوم:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "الدفتر"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "ابحث"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "أي وقت"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "اليوم"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "منذ أمس"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "الأسبوع الماضي"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "الشهر الماضي"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "السنة الماضية"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "أي شخص"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "أصدقائي"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "صفي"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "أي شيء"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:83
+msgid "Copy"
+msgstr "انسخ"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:68
+msgid "Start"
+msgstr "ابدأ"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "دفترك خالِ"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "لا مدخلات مطابقة"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "امسح البحث"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "دفترك ممتلئ"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr "من فضلك احذف بعض مُدخلات الدفتر القديمة لإخلاء مساحة للمُدخلات الجديدة."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "أظهر الدفتر"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "اختر عنصرا"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "أغلق"
+
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Resume with"
+msgstr "استعد مع"
+
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start with"
+msgstr "ابدأ مع"
+
+#: ../src/jarabe/journal/palettes.py:91
+msgid "Send to"
+msgstr "أرسل إلى"
+
+#: ../src/jarabe/journal/palettes.py:100
+msgid "View Details"
+msgstr "اعرض التفاصيل"
+
+#: ../src/jarabe/journal/palettes.py:178
+msgid "No friends present"
+msgstr "لا يوجد أصدقاء"
+
+#: ../src/jarabe/journal/palettes.py:183
+msgid "No valid connection found"
+msgstr "لم يُعثر على اتصال سليم"
+
+#: ../src/jarabe/journal/palettes.py:211
+msgid "No activity to resume entry"
+msgstr "لا نشاط لاستكمال المُدخلة"
+
+#: ../src/jarabe/journal/palettes.py:213
+msgid "No activity to start entry"
+msgstr "لا نشاط لبدء المُدخلة"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "أزل الصديق"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "اصنع صديق"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "أطفئ"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "اخرج"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "إعداداتي"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "ادعُ إلى %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "يبدأ..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr "اعرض المصدر"
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "أوقف"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr "ابدأ الآن"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "أظهر المحتويات"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d م.بايت خالية"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "مصدر السيرورة"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "المصدر"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "مصدر حزمة النشاط"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "اعرض مصدر: %r"
+
+#~ msgid "Title"
+#~ msgstr "العنوان"
+
+#~ msgid "Version"
+#~ msgstr "الإصدارة"
+
+#~ msgid "Date"
+#~ msgstr "التاريخ"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "تعذّر الحصول على البيانات المطلوبة للتسجيل."
+
+#~ msgid "Unmount"
+#~ msgstr "افصل"
+
+#~ msgid "Restart"
+#~ msgstr "أعد التشغيل"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr "حقوق النشر محفوظة 2008 لجمعية حاسوب محمول لكل طفل؛ ردهات؛ والمساهمين."
+
+#~ msgid "Encryption Type:"
+#~ msgstr "نوع التعمية:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid "Disconnecting..."
+#~ msgstr "يجري قطع الاتصال..."
+
+#~ msgid "About my XO"
+#~ msgstr "عن حاسوبي"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "اتصل ببوابة شبكة مدرسة"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "يبحث عن بوابة شبكة مدرسة..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "اتصل ببوابة شبكة XO"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "يبحث عن بوابة شبكة XO..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "اتصل بشبكة بسيطة"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "يبدأ شبكة بسيطة"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "شبكة مجهولة"
+
+#~ msgid "Settings"
+#~ msgstr "الإعدادات"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "عنصر الحافظة: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "يجب أن تُدخِل خادوما."
+
+#~ msgid "Control Panel"
+#~ msgstr "لوحة التحكم"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>ح"
+
+#~ msgid "Ring view"
+#~ msgstr "منظور الحلقة"
+
+#~ msgid "Remove from ring"
+#~ msgstr "أزِل من الحلقة"
+
+#~ msgid "Add to ring"
+#~ msgstr "أضِف للحلقة"
+
+#~ msgid "Changes require a sugar restart to take effect."
+#~ msgstr "يتطلب نفاذ التغييرات إعادة تشغيل «سُكّر»."
+
+#~ msgid "Changes require restart to take effect"
+#~ msgstr "يتطلب نفاذ التغييرات إعادة التشغيل."
+
+#~ msgid "Delay in milliseconds:"
+#~ msgstr "التأخير بالملي ثانية:"
+
+#~ msgid "Hot Corners"
+#~ msgstr "الزوايا النشطة"
+
+#~ msgid "Warm Edges"
+#~ msgstr "الحواف المتفاعلة"
+
+#~ msgid "off"
+#~ msgstr "معطّل"
+
+#~ msgid "on"
+#~ msgstr "مفعّل"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "الصلاحية ممنوعة. تحتاج أن تكون الجذر لتشغل الوظيفة المطلوبة."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "خطأ في قراءة المنطقة الزمنية"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "خطأ في نسخ المنطقة الزمنية (من %s): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "يجري تغيير صلاحيات المنطقة الزمنية: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "عَنْ XO هذا"
+
+#~ msgid "Add to journal"
+#~ msgstr "أضِف إلى اليوميات"
+
+#~ msgid "Reboot"
+#~ msgstr "أعِد التشغيل"
+
+#~ msgid "My Battery life"
+#~ msgstr "عمر بطاريتي"
+
+#~ msgid "Battery charging"
+#~ msgstr "البطاريّة تشحن"
+
+#~ msgid "Battery discharging"
+#~ msgstr "البطاريّة تُفرّغ"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "البطارية مشحونة تماما"
+
+#~ msgid "Invite"
+#~ msgstr "ادعُ"
+
+#~ msgid "Text"
+#~ msgstr "نص"
+
+#~ msgid "Image"
+#~ msgstr "صورة"
+
+#~ msgid "Private"
+#~ msgstr "خاص"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "جِوارِي"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "نشاط %s"
+
+#~ msgid "Share with:"
+#~ msgstr "شارِك مع:"
+
+#~ msgid "Undo"
+#~ msgstr "تراجع"
+
+#~ msgid "Redo"
+#~ msgstr "أعِد"
+
+#~ msgid "Paste"
+#~ msgstr "الصق"
+
+#~ msgid "Keep error"
+#~ msgstr "خطأ في الحفظ"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "خطأ في الحفظ: ستُفقد كل التغييرات"
+
+#~ msgid "Don't stop"
+#~ msgstr "لا تتوقف"
+
+#~ msgid "Stop anyway"
+#~ msgstr "توقف على أي حال"
+
+#~ msgid "Continue"
+#~ msgstr "واصِل"
+
+#~ msgid "OK"
+#~ msgstr "حسنا"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d سنة"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d سنوات"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d شهر"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d شهور"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d أسبوع"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d أسابيع"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d يوم"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d أيام"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d ساعة"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d ساعات"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d دقيقة"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d دقائق"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d ثانية"
+
+#~ msgid " and "
+#~ msgstr " و "
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#, python-format
+#~ msgid ", "
+#~ msgstr "، "
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#, python-format
+#~ msgid "No matching entries "
+#~ msgstr "لا نتائج مطابقة "
diff --git a/shell/po/ay.po b/shell/po/ay.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/ay.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/bg.po b/shell/po/bg.po
new file mode 100644
index 0000000..6f1700a
--- /dev/null
+++ b/shell/po/bg.po
@@ -0,0 +1,454 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-02-09 00:30-0500\n"
+"PO-Revision-Date: 2008-03-01 13:14-0500\n"
+"Last-Translator: Alexander Todorov <atodorov@redhat.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../src/intro/intro.py:67
+msgid "Name:"
+msgstr "Име:"
+
+#: ../src/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "Натиснете, за да смените цвета:"
+
+#: ../src/intro/intro.py:146
+msgid "Back"
+msgstr "Назад"
+
+#: ../src/intro/intro.py:160
+msgid "Done"
+msgstr "Затваряне"
+
+#: ../src/intro/intro.py:163
+msgid "Next"
+msgstr "Следващ"
+
+#: ../src/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "Изтриване на приятел"
+
+#: ../src/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "Създаване на приятел"
+
+#: ../src/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "Покани в %s"
+
+#: ../src/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "Премахване"
+
+#: ../src/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "Отваряне"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "Добави към дневника"
+
+#: ../src/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Обект в паметта: %s."
+
+#: ../src/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "Тип ключ:"
+
+#: ../src/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "Тип удостоверяване:"
+
+#: ../src/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "Вид криптиране:"
+
+#: ../src/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "Стартиране..."
+
+#: ../src/view/home/activitiesdonut.py:104 ../src/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "Продължаване"
+
+#: ../src/view/home/activitiesdonut.py:111
+msgid "Stop"
+msgstr "Стоп"
+
+#: ../src/view/Shell.py:285
+msgid "Screenshot"
+msgstr "Снимка на екрана"
+
+#: ../src/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "Рестартиране"
+
+#: ../src/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "Изключване"
+
+#: ../src/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "Регистриране"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../src/view/home/MeshBox.py:90 ../src/view/home/MeshBox.py:197
+#: ../src/view/devices/network/wireless.py:113
+#: ../src/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "Отделяне..."
+
+#: ../src/view/home/MeshBox.py:195 ../src/view/devices/network/mesh.py:37
+#: ../src/view/devices/network/mesh.py:62
+#: ../src/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "Mesh мрежа"
+
+#: ../src/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "Присъединяване"
+
+#: ../src/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "Статус на батерията"
+
+#: ../src/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "Батерията се зарежда"
+
+#: ../src/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "Батерията се разрежда"
+
+#: ../src/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "Батерията е напълно заредена"
+
+#: ../src/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "Без свързаност"
+
+#: ../src/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "Канал"
+
+# взето от руския превод
+#: ../src/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "Съседи"
+
+#: ../src/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "Група"
+
+#: ../src/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "Начало"
+
+#: ../src/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "Дейност"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "Сподели с:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "Личен"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "Моите съседи"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "Запазване"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "Отмяна"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "Възстановяване"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "Копиране"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "Поставяне"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s занятие"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "Грешка при запис"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "Грешка при запис: всички промени ще бъдат изгубени"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "Без спиране"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr "Спиране винаги"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "Отказ"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "Ок"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "Продължение"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "Добре"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d година"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d години"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d месец"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d месеца"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d седмица"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d седмици"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d ден"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d дни"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d час"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d часа"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d минута"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d минути"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d секунда"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d секунди"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr " и "
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ", "
+
+#: ../src/controlpanel/control.py:219
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Моля, рестартирайте графичната среда, за да влязат в сила промените.\n"
+
+#: ../src/controlpanel/control.py:273
+msgid "Error in specified color modifiers."
+msgstr "Грешка в зададените цветови модификатори."
+
+#: ../src/controlpanel/control.py:276
+msgid "Error in specified colors."
+msgstr "Грешка в зададените цветове."
+
+#: ../src/controlpanel/control.py:312
+msgid "off"
+msgstr "изключен"
+
+#: ../src/controlpanel/control.py:314
+msgid "on"
+msgstr "включен"
+
+#: ../src/controlpanel/control.py:316
+msgid "State is unknown."
+msgstr "Непознато състояние."
+
+#: ../src/controlpanel/control.py:336
+msgid "Error in specified radio argument use on/off."
+msgstr "Грешка в зададения аргумент, използвайте вкл/изкл."
+
+#: ../src/controlpanel/control.py:340
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+"Отказано е позволение. Трябва да сте администратор, за да изпълните този "
+"метод."
+
+#: ../src/controlpanel/control.py:370
+msgid "Error in reading timezone"
+msgstr "Грешка при прочитане на времева зона"
+
+#: ../src/controlpanel/control.py:401
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "Грешка при копиране на времева зона (от %s): %s"
+
+#: ../src/controlpanel/control.py:406
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "Замяна на позволенията за времева зона: %s"
+
+#: ../src/controlpanel/control.py:416
+msgid "Error timezone does not exist."
+msgstr "Грешка, времевата зона не съществува."
+
+#: ../src/controlpanel/control.py:421 ../src/controlpanel/control.py:440
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "Отказан е достъп до %s. Моля, създайте стандартни настойки."
+
+#: ../src/controlpanel/control.py:467
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Не може да бъде определен езикът с код=%s."
+
+#: ../src/controlpanel/control.py:477
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Съжалявам, но не говоря '%s'."
+
+#: ../src/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "Свързан към училищният Mash портал"
+
+#: ../src/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "Търсене на училищем Mesh портал..."
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "Свързан към Mesh мрежа от лаптопи XO"
+
+#: ../src/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Търсене на Mesh мрежа от лаптопи XO..."
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "Свързан към обикновенна Mesh мрежа"
+
+#: ../src/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "Стартиране на обикновенна Mesh мрежа"
+
+#: ../src/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "Непозната Mesh мрежа"
+
+#: ../src/view/home/HomeBox.py:175 ../src/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr "Относно този лаптоп"
+
+#: ../src/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr "Не е наличен"
+
+#: ../src/controlpanel/cmd.py:27
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"Използване: sugar-control-panel [ опции ] ключ [ аргументи ... ] \n"
+" Управление на работната среда. \n"
+" Опции: \n"
+" -h показване на помоща \n"
+" -l списък на всички опции \n"
+" -h ключ показване на информация за ключа \n"
+" -g ключ прочитане на текущата стойност на ключа \n"
+" -s ключ задаване на нова стойност на ключа \n"
+" "
+
+#: ../src/controlpanel/cmd.py:55 ../src/controlpanel/cmd.py:67
+#: ../src/controlpanel/cmd.py:74
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: ключ=%s - непозволена опция"
+
+#: ../src/controlpanel/cmd.py:80
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
diff --git a/shell/po/bi.po b/shell/po/bi.po
new file mode 100644
index 0000000..63d4e34
--- /dev/null
+++ b/shell/po/bi.po
@@ -0,0 +1,764 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-25 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/window.py:93 ../src/controlpanel/aboutme/view.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/window.py:125
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/window.py:175 ../src/journal/detailview.py:119
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/window.py:189 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/window.py:192
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:60
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:63
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:92
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:51
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:56 ../src/view/clipboardmenu.py:78
+msgid "Open"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:61 ../src/view/home/HomeBox.py:84
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:83
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:228
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:17
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:31
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:36
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/view/Shell.py:251
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:78
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:80
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:87 ../src/view/palettes.py:120
+#: ../src/journal/journaltoolbox.py:335 ../src/journal/palettes.py:75
+msgid "Erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:117
+msgid "Software Update"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:118
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:122 ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:124 ../src/controlpanel/gui.py:273
+msgid "Later"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:127
+msgid "Check now"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:261
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:262
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:320
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:321
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:159
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:166
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:218 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:221 ../src/view/devices/network/wireless.py:125
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/view/home/MeshBox.py:309 ../src/view/palettes.py:61
+#: ../src/journal/journaltoolbox.py:399 ../src/journal/palettes.py:57
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:314 ../src/view/frame/activitiestray.py:206
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:125
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:128
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:143
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/controlpanel/cmd.py:35
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:48
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:305
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:42 ../src/controlpanel/gui.py:265
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:264
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:268
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:277
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:76
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:87
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:90
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:32
+#: ../src/controlpanel/aboutme/__init__.py:22
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/model.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:55
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:64
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:87
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:96
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:111
+msgid "Sugar:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:126
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:148
+msgid "Copyright and License"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:156
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:163
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:175
+msgid "Full license:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/__init__.py:21
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/datetime/model.py:89
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/datetime/view.py:68
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/frame/model.py:38 ../src/controlpanel/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:114
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:131
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/language/view.py:70
+#: ../src/controlpanel/language/__init__.py:21
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:62
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:82
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:28
+#: ../src/controlpanel/network/__init__.py:21
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:54
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:62
+msgid "Turn of the wireless radio to save battery life"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:75
+msgid "Radio"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:91
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:100
+msgid "Discard network history"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:113
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:122
+msgid "Server:"
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:55
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:84
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:211
+msgid "Decline"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:107
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:189
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:401
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:442
+msgid "Triangle"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:295
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:296
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:298
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:299
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:420
+msgid "Settings"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:425
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:430
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:436
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/view/palettes.py:104 ../src/journal/journaltoolbox.py:402
+#: ../src/journal/palettes.py:59
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:138
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:142
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:191
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:215
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:62
+msgid "Search"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:119
+msgid "Anytime"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:121
+msgid "Today"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:123
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/journal/journaltoolbox.py:125
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/journal/journaltoolbox.py:127
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/journal/journaltoolbox.py:129
+msgid "Past year"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:136
+msgid "Anyone"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:138
+msgid "My friends"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:139
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/journal/journaltoolbox.py:255
+msgid "Anything"
+msgstr ""
+
+#. TODO: Add "Start with" menu item
+#: ../src/journal/journaltoolbox.py:325 ../src/journal/palettes.py:67
+msgid "Copy"
+msgstr ""
+
+#: ../src/journal/collapsedentry.py:248 ../src/journal/expandedentry.py:176
+#: ../src/journal/palettes.py:51
+msgid "Untitled"
+msgstr ""
+
+#: ../src/journal/journalactivity.py:119 ../src/journal/volumesmanager.py:57
+msgid "Journal"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:222
+msgid "No preview"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:241
+msgid "Participants:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:266
+msgid "Description:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:292
+msgid "Tags:"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:134
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:139
+msgid "Close"
+msgstr ""
+
+#: ../src/journal/volumestoolbar.py:93
+msgid "Unmount"
+msgstr ""
+
+#: ../src/journal/misc.py:95
+msgid "No date"
+msgstr ""
+
+#: ../src/journal/listview.py:39
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/journal/listview.py:40
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/journal/modalalert.py:59
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/journal/modalalert.py:63
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/journal/modalalert.py:75
+msgid "Show Journal"
+msgstr ""
diff --git a/shell/po/bn.po b/shell/po/bn.po
new file mode 100644
index 0000000..45ede9f
--- /dev/null
+++ b/shell/po/bn.po
@@ -0,0 +1,419 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: Update 1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2007-12-23 10:33+0000\n"
+"Last-Translator: Khandakar Mujahidul Islam <suzan229@gmail.com>\n"
+"Language-Team: Bengali <core@bengalinux.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "নাম:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "রং পরিবর্তন করতে ক্লিক:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "পেছনে"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "করা হয়েছে"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "পরবর্তী"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "বন্ধু মোছো"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "বন্ধু বানাও"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "%s কে নিমণ্ত্রণ"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "মোছো"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "খোলো"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "জার্নালে লেখ"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "ক্লীপবোর্ড বস্তু: %s।"
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "কী ধরণ:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "পরিচয় প্রমানের ধরণ:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "এনক্রিপশন ধরণ:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "শুরু হচ্ছে..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "পুনরায় শুরু করুন"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "থামাও"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "স্ক্রীণশট"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "পুনরায় চালু"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "বন্ধ করো"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "রেজিস্টার"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "সংযোগ বিচ্ছিন্ন..."
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "মেশ নেটওয়ার্ক"
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "যোগ দাও"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "আমার ব্যাটারীর জীবনসীমা"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "ব্যাটারী চার্জ হচ্ছে"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "ব্যাটারী চার্জ কমে যাচ্ছে"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "ব্যাটারী পুরোপুরি চার্জ হয়েছে"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "সংযোগ বিচ্ছিন্ন"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "চ্যানেল"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "ছোটবেলা"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "দল"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "বাড়ি"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "সক্রিয়তা"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "ভাগাভাগি করো:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "ব্যাক্তিগত"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "আমার ছেলেবেলা"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "রাখো"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "বাতিল করো"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "আবার করো"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "কপি"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "সাঁটো"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s সক্রিয়তা"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "ত্রুটি রেখে দাও"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "ত্রুটি রেখে দাও: সব পরিবর্তন হারিয়ে যাবে"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "থামিও না"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr "যে কোন ভাবে থামো"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "বাতিল"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "ঠিক আছে"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "এগিয়ে যাও"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "ঠিক আছে"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d বছর"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d বছর"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d মাস"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d মাস"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d সপ্তাহ"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d সপ্তাহ"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d দিন"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d দিন"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d ঘন্টা"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d ঘন্টা"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d মিনিট"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d মিনিট"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d সেকেন্ড"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d সেকেন্ড"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr " এবং "
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ", "
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "তোমার পরিবর্তন কার্যকর করার জন্য সুগার পুনরায় চালু করতে হবে।\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "উল্লেখিত রং পরিবর্তকে ত্রুটি।"
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "উল্লেখিত রং এ ত্রুটি।"
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "off"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "on"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "অবস্থানটি অজানা।"
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr "উল্লেখিত রেডিও প্রেরিত মান ব্যবহার on/off তে ত্রুটি।"
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr "অনুমতি প্রত্যাখ্যাত। এই পন্থাটি চালাতে তোমাকে root হিসেবে কাজ করতে হবে।"
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "সময় জোন পড়তে ত্রুটি"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "সময় জোন (%s হতে) কপি করায় ত্রুটি: %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "সময় জোনের অনুমতি পরিবর্তন: %s"
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr "ত্রুটিযুক্ত সময় জোনের অস্তিত্ব নেই।"
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "%s এ প্রবেশ করতে পারে নি। প্রমাণ মানসমূহ তৈরি করো।"
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "কোড=%s এর জন্য কোন ভাষা নির্ধারণ করা যায় নি।"
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "দুঃখিত আমি '%s' বলতে পারি না।"
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "একটি স্কুলের মেশ পোর্টালে সংযুক্ত"
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "একটি স্কুল মেশ পোর্টাল খুজছি..."
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "একটি জো(XO) মেশ পোর্টালে সংযুক্ত"
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "একটি জো(XO) মেশ পোর্টাল খুজছি..."
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "একটি সাধারণ মেশ এ সংযুক্ত"
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "একটি সাধারণ মেশ চালু করছি"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "অজানা মেশ"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr "XO সম্বন্ধে"
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr "পাওয়া যায় নি"
diff --git a/shell/po/bn_IN.po b/shell/po/bn_IN.po
new file mode 100644
index 0000000..45ede9f
--- /dev/null
+++ b/shell/po/bn_IN.po
@@ -0,0 +1,419 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: Update 1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2007-12-23 10:33+0000\n"
+"Last-Translator: Khandakar Mujahidul Islam <suzan229@gmail.com>\n"
+"Language-Team: Bengali <core@bengalinux.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "নাম:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "রং পরিবর্তন করতে ক্লিক:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "পেছনে"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "করা হয়েছে"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "পরবর্তী"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "বন্ধু মোছো"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "বন্ধু বানাও"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "%s কে নিমণ্ত্রণ"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "মোছো"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "খোলো"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "জার্নালে লেখ"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "ক্লীপবোর্ড বস্তু: %s।"
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "কী ধরণ:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "পরিচয় প্রমানের ধরণ:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "এনক্রিপশন ধরণ:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "শুরু হচ্ছে..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "পুনরায় শুরু করুন"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "থামাও"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "স্ক্রীণশট"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "পুনরায় চালু"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "বন্ধ করো"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "রেজিস্টার"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "সংযোগ বিচ্ছিন্ন..."
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "মেশ নেটওয়ার্ক"
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "যোগ দাও"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "আমার ব্যাটারীর জীবনসীমা"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "ব্যাটারী চার্জ হচ্ছে"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "ব্যাটারী চার্জ কমে যাচ্ছে"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "ব্যাটারী পুরোপুরি চার্জ হয়েছে"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "সংযোগ বিচ্ছিন্ন"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "চ্যানেল"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "ছোটবেলা"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "দল"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "বাড়ি"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "সক্রিয়তা"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "ভাগাভাগি করো:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "ব্যাক্তিগত"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "আমার ছেলেবেলা"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "রাখো"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "বাতিল করো"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "আবার করো"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "কপি"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "সাঁটো"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s সক্রিয়তা"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "ত্রুটি রেখে দাও"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "ত্রুটি রেখে দাও: সব পরিবর্তন হারিয়ে যাবে"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "থামিও না"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr "যে কোন ভাবে থামো"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "বাতিল"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "ঠিক আছে"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "এগিয়ে যাও"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "ঠিক আছে"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d বছর"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d বছর"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d মাস"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d মাস"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d সপ্তাহ"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d সপ্তাহ"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d দিন"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d দিন"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d ঘন্টা"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d ঘন্টা"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d মিনিট"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d মিনিট"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d সেকেন্ড"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d সেকেন্ড"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr " এবং "
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ", "
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "তোমার পরিবর্তন কার্যকর করার জন্য সুগার পুনরায় চালু করতে হবে।\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "উল্লেখিত রং পরিবর্তকে ত্রুটি।"
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "উল্লেখিত রং এ ত্রুটি।"
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "off"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "on"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "অবস্থানটি অজানা।"
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr "উল্লেখিত রেডিও প্রেরিত মান ব্যবহার on/off তে ত্রুটি।"
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr "অনুমতি প্রত্যাখ্যাত। এই পন্থাটি চালাতে তোমাকে root হিসেবে কাজ করতে হবে।"
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "সময় জোন পড়তে ত্রুটি"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "সময় জোন (%s হতে) কপি করায় ত্রুটি: %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "সময় জোনের অনুমতি পরিবর্তন: %s"
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr "ত্রুটিযুক্ত সময় জোনের অস্তিত্ব নেই।"
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "%s এ প্রবেশ করতে পারে নি। প্রমাণ মানসমূহ তৈরি করো।"
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "কোড=%s এর জন্য কোন ভাষা নির্ধারণ করা যায় নি।"
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "দুঃখিত আমি '%s' বলতে পারি না।"
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "একটি স্কুলের মেশ পোর্টালে সংযুক্ত"
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "একটি স্কুল মেশ পোর্টাল খুজছি..."
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "একটি জো(XO) মেশ পোর্টালে সংযুক্ত"
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "একটি জো(XO) মেশ পোর্টাল খুজছি..."
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "একটি সাধারণ মেশ এ সংযুক্ত"
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "একটি সাধারণ মেশ চালু করছি"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "অজানা মেশ"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr "XO সম্বন্ধে"
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr "পাওয়া যায় নি"
diff --git a/shell/po/ca.po b/shell/po/ca.po
new file mode 100644
index 0000000..a9ab315
--- /dev/null
+++ b/shell/po/ca.po
@@ -0,0 +1,438 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# revisar
+#, python-format
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2008-01-14 17:19+0000\n"
+"Last-Translator: Jaume <jaume@nualart.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "Nom:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "Clic per a canviar de color:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Enrere"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "Fet"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "Següent"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "Esborrar amic/ga"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "Fer amic/ga"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "Convidar a %s"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "Eliminar"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "Obrir"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "Afegir al diari"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Objecte del porta-retalls: %s"
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "Tipus de clau:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "Tipus d'autentificació:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "Tipus d'encriptació:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "Arrencant ..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "Reprendre"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "Aturar"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "Captura de pantalla"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "Reiniciar"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "Aturar"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "Registre"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "Desconnecta ..."
+
+# Aquí he agafat l'original "mesh", en comptes de fer-ne una traducció
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+#: ../src/view/home/MeshBox.py:195
+#: ../src/view/devices/network/mesh.py:37
+#: ../src/view/devices/network/mesh.py:62
+#: ../src/view/devices/network/mesh.py:66
+#, fuzzy
+msgid "Mesh Network"
+msgstr "Xarxa Mesh"
+
+# mmm, potser més simple?
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "Uneix-t'hi"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "Vida de la bateria"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "Carregant bateria"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "Descarregant bateria"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "Bateria plena"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "Desconnectat"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "Canal"
+
+# aquí cal pensar si es millorÑ barri, veinatge, maquines veines,....
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "Veïns"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "Grup"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "Inici"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "Activitat"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "Compartir amb:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "Privat"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "Els meus veïns"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "Desfer"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "Refer"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "Copia"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "Enganxa"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s Activitat"
+
+# revisar
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "Manté l'error"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "Manté l'error: tots els canvis es perdran"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "No t'aturis"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "Cancel·lar"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "D'acord"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "Continuar"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "D'acord"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d any"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d anys"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d mes"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d mesos"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d setmana"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d setmanes"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d dia"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d dies"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d hora"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d hores"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d minut"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d minuts"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d segon"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d segons"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr "i"
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ","
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Per aplicar els canvis, cal que reiniciar el sugar.\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "Error en els modificadors de color especificats"
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "Error en els colors especificats"
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "apagar"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "arrancar"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "Status deconegut"
+
+# dubtes:
+# 1- manca una coma al text original
+# 2- He posat on/off
+#: ../shell/controlpanel/control.py:332
+#: ../src/controlpanel/control.py:336
+#, fuzzy
+msgid "Error in specified radio argument use on/off."
+msgstr "Error en l'argument de ràdio especificat, useu on/off"
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr "Permís denegat: cal que ser root per aquesta operació"
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "Error en llegir la zona horària"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "Error en copiar la zona horària (des de %s): %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "Canviant permisos de zona horària: %s"
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr "Error: aquesta zona horària no existeix"
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "No es pot accedir a %s. Crea una configuració estàndar."
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "La llengua que té com a codi code=%s no es pot determinar."
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Ho sento, no parlo '%s'."
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "Connectat al Portal de la Xarxa de l'Escola"
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "Cercant el Portal de la Xarxa de l'Escola ..."
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "Connectat a un Portal de Xarxa XO"
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Cercant un Portal de Xarxa XO ..."
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "Connectat a una xarxa simple"
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "Arrancant una xarxa simple"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "Xarxa desconeguda"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+#: ../src/view/home/HomeBox.py:175
+#: ../src/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr "Sobre aquest XO"
+
+#: ../shell/view/home/HomeBox.py:222
+#: ../src/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr "No disponible"
diff --git a/shell/po/cpp.po b/shell/po/cpp.po
new file mode 100644
index 0000000..93c6b6e
--- /dev/null
+++ b/shell/po/cpp.po
@@ -0,0 +1,958 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-31 00:30-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:26
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:59
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:68
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:90
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:99
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:114
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:130
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:145
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:168
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:176
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:183
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:195
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:19
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:32
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:56
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:64
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:77
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:93
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:102
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:115
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:123
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:133
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:56
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:153
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:40
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:104
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:109
+#: ../src/jarabe/desktop/meshbox.py:246
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:113
+#: ../extensions/deviceicon/network.py:166
+#: ../src/jarabe/desktop/meshbox.py:252
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:126
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:141
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:169
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:46
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:128
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:131
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:50
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:196
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:205
+#: ../src/jarabe/frame/zoomtoolbar.py:42
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:212
+msgid "Document"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:226
+#: ../src/jarabe/journal/objectchooser.py:141
+msgid "Close"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:272
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:273
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:276
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281 ../src/jarabe/desktop/homebox.py:113
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:111
+#: ../src/jarabe/frame/activitiestray.py:683
+#: ../src/jarabe/frame/activitiestray.py:762
+#: ../src/jarabe/frame/activitiestray.py:790
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:334
+msgid "Ok"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:114
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:196
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:341
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:408
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:449
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:329
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:666
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:67
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:69
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73 ../src/jarabe/frame/clipboardmenu.py:62
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:76
+#: ../src/jarabe/journal/journaltoolbox.py:357
+#: ../src/jarabe/journal/palettes.py:112 ../src/jarabe/view/palettes.py:127
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:106
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:107
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:116
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:233
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:234
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:296
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:297
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:304
+msgid "Resume by default"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:130
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:134
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:440
+#: ../src/jarabe/frame/activitiestray.py:707
+#: ../src/jarabe/journal/journaltoolbox.py:425
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:62
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:445
+#: ../src/jarabe/frame/activitiestray.py:221
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:18
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:35
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:40
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:226
+#: ../src/jarabe/frame/activitiestray.py:655
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:608
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:610
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:612
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:629
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:640
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:673
+#: ../src/jarabe/frame/activitiestray.py:780
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:751
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:47
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:36
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:38
+msgid "Group"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:40
+msgid "Home"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/collapsedentry.py:258
+#: ../src/jarabe/journal/expandedentry.py:159
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:205
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:224
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:247
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:273
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:65
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:124
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:141
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:271
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:347
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:75 ../src/jarabe/view/palettes.py:111
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:40
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:41
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:369
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:136
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:61
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:64
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:81
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:86
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:91
+msgid "Restart"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:96
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:131
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:43
+msgid "Starting..."
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:73
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:145
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:149
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:201
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:223 ../src/jarabe/view/palettes.py:272
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:248
+msgid "Unmount"
+msgstr ""
diff --git a/shell/po/cs.po b/shell/po/cs.po
new file mode 100644
index 0000000..63d4e34
--- /dev/null
+++ b/shell/po/cs.po
@@ -0,0 +1,764 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-25 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/window.py:93 ../src/controlpanel/aboutme/view.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/window.py:125
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/window.py:175 ../src/journal/detailview.py:119
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/window.py:189 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/window.py:192
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:60
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:63
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:92
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:51
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:56 ../src/view/clipboardmenu.py:78
+msgid "Open"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:61 ../src/view/home/HomeBox.py:84
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:83
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:228
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:17
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:31
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:36
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/view/Shell.py:251
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:78
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:80
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:87 ../src/view/palettes.py:120
+#: ../src/journal/journaltoolbox.py:335 ../src/journal/palettes.py:75
+msgid "Erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:117
+msgid "Software Update"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:118
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:122 ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:124 ../src/controlpanel/gui.py:273
+msgid "Later"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:127
+msgid "Check now"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:261
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:262
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:320
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:321
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:159
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:166
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:218 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:221 ../src/view/devices/network/wireless.py:125
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/view/home/MeshBox.py:309 ../src/view/palettes.py:61
+#: ../src/journal/journaltoolbox.py:399 ../src/journal/palettes.py:57
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:314 ../src/view/frame/activitiestray.py:206
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:125
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:128
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:143
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/controlpanel/cmd.py:35
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:48
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:305
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:42 ../src/controlpanel/gui.py:265
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:264
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:268
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:277
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:76
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:87
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:90
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:32
+#: ../src/controlpanel/aboutme/__init__.py:22
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/model.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:55
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:64
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:87
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:96
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:111
+msgid "Sugar:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:126
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:148
+msgid "Copyright and License"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:156
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:163
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:175
+msgid "Full license:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/__init__.py:21
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/datetime/model.py:89
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/datetime/view.py:68
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/frame/model.py:38 ../src/controlpanel/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:114
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:131
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/language/view.py:70
+#: ../src/controlpanel/language/__init__.py:21
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:62
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:82
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:28
+#: ../src/controlpanel/network/__init__.py:21
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:54
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:62
+msgid "Turn of the wireless radio to save battery life"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:75
+msgid "Radio"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:91
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:100
+msgid "Discard network history"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:113
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:122
+msgid "Server:"
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:55
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:84
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:211
+msgid "Decline"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:107
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:189
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:401
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:442
+msgid "Triangle"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:295
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:296
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:298
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:299
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:420
+msgid "Settings"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:425
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:430
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:436
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/view/palettes.py:104 ../src/journal/journaltoolbox.py:402
+#: ../src/journal/palettes.py:59
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:138
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:142
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:191
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:215
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:62
+msgid "Search"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:119
+msgid "Anytime"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:121
+msgid "Today"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:123
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/journal/journaltoolbox.py:125
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/journal/journaltoolbox.py:127
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/journal/journaltoolbox.py:129
+msgid "Past year"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:136
+msgid "Anyone"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:138
+msgid "My friends"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:139
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/journal/journaltoolbox.py:255
+msgid "Anything"
+msgstr ""
+
+#. TODO: Add "Start with" menu item
+#: ../src/journal/journaltoolbox.py:325 ../src/journal/palettes.py:67
+msgid "Copy"
+msgstr ""
+
+#: ../src/journal/collapsedentry.py:248 ../src/journal/expandedentry.py:176
+#: ../src/journal/palettes.py:51
+msgid "Untitled"
+msgstr ""
+
+#: ../src/journal/journalactivity.py:119 ../src/journal/volumesmanager.py:57
+msgid "Journal"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:222
+msgid "No preview"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:241
+msgid "Participants:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:266
+msgid "Description:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:292
+msgid "Tags:"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:134
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:139
+msgid "Close"
+msgstr ""
+
+#: ../src/journal/volumestoolbar.py:93
+msgid "Unmount"
+msgstr ""
+
+#: ../src/journal/misc.py:95
+msgid "No date"
+msgstr ""
+
+#: ../src/journal/listview.py:39
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/journal/listview.py:40
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/journal/modalalert.py:59
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/journal/modalalert.py:63
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/journal/modalalert.py:75
+msgid "Show Journal"
+msgstr ""
diff --git a/shell/po/da.po b/shell/po/da.po
new file mode 100644
index 0000000..f6abf2d
--- /dev/null
+++ b/shell/po/da.po
@@ -0,0 +1,1227 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-09-05 00:31-0400\n"
+"PO-Revision-Date: 2010-01-25 03:48+0200\n"
+"Last-Translator: Chris <cjl@laptop.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 2.0.1\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Du skal skrive et navn."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "streg: farve=%s nuance=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "streg: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "fyld: farve=%s nuance=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "fyld: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Fejl i angivne farvetilrettere."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Fejl i angivne farver."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+#, fuzzy
+msgid "Click to change your color:"
+msgstr "Klik for at ændre farve:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Ikke tilgængelig"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Fejl tidszone eksisterer ikke."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr "Tidszone"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Værdi skal være et heltal."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Desværre jeg taler ikke '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Tilstand er ukendt."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Fejl i angivne radioargument brug on/off."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Fejl i angivne argument brug 0/1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Trådløs"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Sluk for den trådløse radio for at spare på batteriet"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Radio"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+"Drop netværkshistorik hvis du har problemer med at forbinde til netværket"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Drop netværkshistorik"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Server:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Strøm"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Strømstyring"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Automatisk strømstyring (øger batterilevetiden)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr "Ekstrem strømstyring (slukker trådløs radio, øger batterilevetid)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+#, fuzzy
+msgid "Software update"
+msgstr "Software-opdatering"
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+#, fuzzy
+msgid "None"
+msgstr "Færdig"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Mit batteri"
+
+#: ../extensions/deviceicon/battery.py:137
+#, fuzzy
+msgid "Removed"
+msgstr "Fjern"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Oplader"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Meget lidt strøm tilbage"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d endnu"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Opladet"
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr "IP-adresse: %s"
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr "Afbryd..."
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:264
+msgid "Connecting..."
+msgstr "Forbinder..."
+
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:270
+msgid "Connected"
+msgstr "Tilsluttet"
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr "Kanal"
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Mine højttalere"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Tænd for lyden"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Sluk for lyden"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Gruppe"
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Hjem"
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Aktivitet"
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr "Skærmaftryk"
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: ADVARSEL: fandt flere end ét valg med samme navn: %s "
+"modul: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s ikke et tilgængeligt valg"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Anvendelse: sugar-control-panel [ valg ] nøgle [ argumenter ... ] \n"
+" Styring af sukker-miljøet. \n"
+" Valg: \n"
+" -h vis denne hjælpebesked og afslut \n"
+" -l vis liste over alle tilgængelige valg \n"
+" -h key vis information om denne nøgle \n"
+" -g key hent den nuværende værdi for nøglen \n"
+" -s key angiv den nuværende værdi for nøglen \n"
+" -c key nulstil den nuværende værdi for nøglen \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "For at dine ændringer træder i kraft skal du genstarte sukker.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr "Advarsel"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Ændringer kræver genstart"
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr "Fortryd ændringer"
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Senere"
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr "Genstart nu"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "Færdig"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr "Fortryd"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr "Bekræft sletning"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Bekræft sletning: Vil du virkeligt permanent slette %s?"
+
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:407
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr "Slet"
+
+#: ../src/jarabe/desktop/activitieslist.py:428
+msgid "Remove favorite"
+msgstr "Fjern favorit"
+
+#: ../src/jarabe/desktop/activitieslist.py:432
+msgid "Make favorite"
+msgstr "Opret favorit"
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr "Registrering mislykkedes"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr "Registrering lykkedes"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr "Du er nu registreret ved din skoleserver."
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr "Registrér"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Software-opdatering"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"Opdatér dine aktiviteter for at sikre kompatibilitet med din nye software"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Undersøg nu"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Listevisning"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Favoritvisning"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr "Nøgletype:"
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr "Ægthedstype:"
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr "Forbind"
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr "Afbryd"
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:466
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr "Genoptag"
+
+#: ../src/jarabe/desktop/meshbox.py:471
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr "Tilslut"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "Kan ikke forbinde til serveren."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "Serveren kunne ikke gennemføre forespørgslen."
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr "Afslå"
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52 ../src/jarabe/view/palettes.py:218
+msgid "Remove"
+msgstr "Fjern"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "Åbn"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "Åbn med"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Nabolag"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "Klik for at ændre farve:"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Tilbage"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "Næste"
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "Uden navn"
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr "Ingen smugkig"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr "Ingen dato"
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr "Deltagere:"
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr "Beskrivelse:"
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr "Mærkater:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Logbog"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Søg"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "Nårsomhelst"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Idag"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Siden igår"
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Seneste uge"
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Seneste måned"
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Seneste år"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Enhver"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Mine venner"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Min klasse"
+
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Hvadsomhelst"
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "Kopiér"
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr "Start"
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr "Din logbog er tom"
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr "Ingen modsvarende emner"
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Din logbog er fuld"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr "Slet nogle logbogsindlæg for at frigøre plads for nye indlæg."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Vis logbog"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Vælg et objekt"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Luk"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Fjern ven"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Opret ven"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Starter..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr "Stop"
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr "Vis indhold"
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB ledig"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "Kan ikke skaffe data nødvendig for registrering."
+
+#~ msgid "Restart"
+#~ msgstr "Genstart"
diff --git a/shell/po/de.po b/shell/po/de.po
new file mode 100644
index 0000000..5ca6d88
--- /dev/null
+++ b/shell/po/de.po
@@ -0,0 +1,1711 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# This file is distributed under the same license as the PACKAGE package.
+# Fabian Affolter <fab@fedoraproject.org>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-03-11 00:31-0500\n"
+"PO-Revision-Date: 2010-03-29 01:49+0200\n"
+"Last-Translator: Markus <m.slg@gmx.de>\n"
+"Language-Team: German <fedora-trans-de@redhat.com>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 2.0.3\n"
+"X-Poedit-Language: German\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Über mich"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Bitte einen Namen eingeben."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "Linie: Farbe=%s Farbton=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "Linie: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "Füllung: Farbe=%s Farbton=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "Füllung: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Fehler in den angegebenen Farbänderungen."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Fehler in den angegebenen Farben."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "Name:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Klicken, um deine Farbe zu wechseln:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Über meinen Computer"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Nicht verfügbar"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Identität"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Seriennummer:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Software"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Version:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "WLAN-Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Copyright und Lizenz"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Sugar ist die grafische Benutzeroberfläche, die du vor die siehst. Sugar ist "
+"freie Software und unterliegt der GNU General Public License. Im Rahmen der "
+"darin festgelegten Bedingungen ist es erlaubt, die Software zu verändern "
+"und/oder Kopien davon zu erstellen und zu verteilen."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Vollständige Lizenz:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Datum & Uhrzeit"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Fehler: unbekannte Zeitzone."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:47
+msgid "Timezone"
+msgstr "Zeitzone"
+
+# (Markus S.) 'Rahmen'? (Vorschlag von hmeyer)
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Rahmen"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Der Wert muss ganzzahlig sein."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "nie"
+
+# (Markus S.) ' unmittelbar'?
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "sofort"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s Sekunden"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Aktivierungsverzögerung"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Ecke"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Kante"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "Tastatur"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "Tastaturmodell"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "Taste(n) zum Layoutwechsel"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "Tastaturlayout(s)"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Sprache"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Zugriff auf ~/.i18n nicht möglich. Erzeuge daher Standardeinstellungen."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Sprache für Code=%s konnte nicht ermittelt werden."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Entschuldigung, ich spreche nicht '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"Sprachen in der gewünschten Reihenfolge hinzufügen. Wenn eine Übersetzung "
+"nicht verfügbar ist, wird die nächste aus der Liste benutzt."
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr "Modem-Konfiguration"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:91
+msgid "Username:"
+msgstr "Benutzername:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:102
+msgid "Password:"
+msgstr "Passwort:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:113
+msgid "Number:"
+msgstr "Nummer:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:124
+msgid "Access Point Name (APN):"
+msgstr "Access-Point-Name (APN):"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:135
+msgid "Personal Identity Number (PIN):"
+msgstr "Persönliche Kennnumer (PIN):"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:146
+msgid "Personal Unblocking Key (PUK):"
+msgstr "Persönlicher Freischaltschlüssel (PUK):"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:167
+msgid ""
+"You will need to provide the following information to set up a mobile "
+"broadband connection to a cellular (3G) network."
+msgstr ""
+"Du musst die folgenden Daten eingeben, um eine Verbindung zu einem "
+"Mobilfunknetz (3G) aufzubauen."
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Netzwerk"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Status ist nicht bekannt."
+
+# (Markus S.) vgl. http://lists.laptop.org/pipermail/localization/2008-July/001232.html
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Fehler im angegebenen Funknetzparameter -- on/off verwenden."
+
+# (Markus S.) vgl. http://lists.laptop.org/pipermail/localization/2008-July/001232.html
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Fehler im angegebenen Parameter -- 0/1 verwenden."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Funknetzwerk"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Schalte das Funknetz aus, um die Lebensdauer der Batterie zu erhöhen."
+
+# (Markus S,) war 'Radio:'
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Funknetz"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+"Verwirf die Netzwerk-Chronik, wenn du Schwierigkeiten hast, dich mit dem "
+"Netzwerk zu verbinden."
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Netzwerk-Chronik verwerfen"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Zusammenarbeit"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"Der Server entspricht dem Raum, in dem du dich befindest; Personen am selben "
+"Server können einander sehen, selbst wenn sie sich nicht im selben Netzwerk "
+"befinden."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Server:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Energieversorgung"
+
+# (Markus S.) vgl. http://lists.laptop.org/pipermail/localization/2008-July/001232.html
+#: ../extensions/cpsection/power/model.py:85
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+"Fehler im automatischen Energieverwaltungsparameter -- on/off verwenden."
+
+# (Markus S.) vgl. http://lists.laptop.org/pipermail/localization/2008-July/001232.html
+#: ../extensions/cpsection/power/model.py:112
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Fehler im extremen Energieverwaltungsparameter -- on/off verwenden."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Energieverwaltung"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Automatische Energieverwaltung (erhöht die Lebensdauer der Batterie)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Extreme Energieverwaltung (deaktiviert das Funknetz, erhöht die Lebensdauer "
+"der Batterie)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Software-Aktualisierung"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"Software-Aktualisierungen beheben Fehler, schließen Sicherheitslücken und "
+"bieten neue Funktionen."
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "Prüfe %s..."
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "Lade %s herunter..."
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "Aktualisiere %s..."
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "Deine Software ist auf dem neuesten Stand."
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "Du kannst %s Update installieren."
+msgstr[1] "Du kannst %s Updates installieren."
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "Suche nach Updates..."
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "Installiere Updates..."
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s Update wurde installiert."
+msgstr[1] "%s Updates wurden installiert."
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "Auswahl installieren"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "Downloadgröße: %s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "Von Version %(current)d auf %(new)s (Größe: %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "Nichts"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1 KB"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f KB"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Meine Batterie"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Entfernt"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Aufladen"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Sehr wenig Ladung verbleibend"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d verbleibend"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Aufgeladen"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "IP-Addresse: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:112
+msgid "Disconnect..."
+msgstr "Verbindung trennen..."
+
+#: ../extensions/deviceicon/network.py:117
+msgid "Create new wireless network"
+msgstr "Neues Funknetzwerk erstellen"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:123
+#: ../extensions/deviceicon/network.py:285
+#: ../src/jarabe/desktop/meshbox.py:247 ../src/jarabe/desktop/meshbox.py:536
+msgid "Connecting..."
+msgstr "Verbinde..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:127
+#: ../extensions/deviceicon/network.py:199
+#: ../extensions/deviceicon/network.py:289
+#: ../src/jarabe/desktop/meshbox.py:253 ../src/jarabe/desktop/meshbox.py:542
+msgid "Connected"
+msgstr "Verbunden"
+
+#: ../extensions/deviceicon/network.py:159
+msgid "Channel"
+msgstr "Kanal"
+
+#: ../extensions/deviceicon/network.py:174
+msgid "Wired Network"
+msgstr "Kabelnetzwerk"
+
+# (Markus S.) War 'Geschwindigkeit'
+#: ../extensions/deviceicon/network.py:202
+msgid "Speed"
+msgstr "Übertragungsrate"
+
+#: ../extensions/deviceicon/network.py:229
+msgid "Wireless modem"
+msgstr "Funkmodem"
+
+#: ../extensions/deviceicon/network.py:277
+msgid "Please wait..."
+msgstr "Bitte warten..."
+
+#: ../extensions/deviceicon/network.py:280
+#: ../src/jarabe/desktop/meshbox.py:163 ../src/jarabe/desktop/meshbox.py:493
+msgid "Connect"
+msgstr "Verbinden"
+
+#: ../extensions/deviceicon/network.py:281
+msgid "Disconnected"
+msgstr "Nicht verbunden"
+
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "Abbrechen"
+
+# (mschlager) war 'Nicht verbunden', ich würde aber eher erwarten, dass das die Beschriftung eines Menüeintrags ist, mit dem man eine Verbindung trennt, was dann in der Folge die Meldung 'Disconnecting...' liefert.
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:167
+msgid "Disconnect"
+msgstr "Verbindung trennen"
+
+#: ../extensions/deviceicon/network.py:292
+msgid "Sim requires Pin/Puk"
+msgstr "Sim benötigt PIN/PUK"
+
+#: ../extensions/deviceicon/network.py:293
+msgid "Authentication Error"
+msgstr "Authentifizierungsfehler"
+
+#: ../extensions/deviceicon/network.py:538
+#, python-format
+msgid "%s's network"
+msgstr "Netzwerk von %s"
+
+#: ../extensions/deviceicon/network.py:605
+#: ../extensions/deviceicon/network.py:664
+msgid "Mesh Network"
+msgstr "Maschennetzwerk"
+
+#: ../extensions/deviceicon/network.py:869
+#, python-format
+msgid "Data sent %d KB / received %d KB"
+msgstr "gesendet %d KB / empfangen %d KB"
+
+#: ../extensions/deviceicon/network.py:880
+msgid "Connection time "
+msgstr "Verbindungsdauer "
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Meine Lautsprecher"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Laut schalten"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Stumm schalten"
+
+# (Markus S.) 'Zelle'?
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "Masche"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Gruppe"
+
+# (Markus S.) war 'Zuhause', vgl. stuffer-sheet
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Startbildschirm"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Aktivität"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "Bildschirmfoto"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "Bildschirmfoto von \"%s\""
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr ""
+"\"Deaktiviert\" fragt bei der Initalisierung nach einem Nicknamen; \"System\" "
+"nutzt den vollständigen UNIX-Benutzernamen."
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Additional directories which can contain updated translations."
+msgstr ""
+"Weitere Verzeichnisse, die aktualisierte Übersetzungen enthalten können."
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Backup URL"
+msgstr "Backup-URL"
+
+#: ../data/sugar.schemas.in.h:4
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"Farbe des XO-Symbols, das überall auf dem Desktop benutzt wird. Die "
+"Zeichenkette setzt sich aus der Linien- und der Füllfarbe zusammen, die "
+"jeweils als RGB-Farben angeben werden. Beispiel: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Corner Delay"
+msgstr "Eckenverzögerung"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font face"
+msgstr "Standard-Schriftart"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default font size"
+msgstr "Standard-Schriftgröße"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Default nick"
+msgstr "Standard-Benutzername"
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the corners."
+msgstr "Verzögerung bei der Aktivierung eines Rahmens über die Ecken."
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Verzögerung bei der Aktivierung eines Rahmens über die Ränder."
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Directory to search for translations"
+msgstr "Verzeichnis zur Suche nach Übersetzungen"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Edge Delay"
+msgstr "Randverzögerung"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Favorites Layout"
+msgstr "Favoriten-Layout"
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Favorites resume mode"
+msgstr "Favoriten-Wiederaufnahmemodus"
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Font face that is used throughout the desktop."
+msgstr "Schriftart, die auf dem Desktop benutzt wird."
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Font size that is used throughout the desktop."
+msgstr "Schriftgröße, die auf dem Desktop benutzt wird."
+
+#: ../data/sugar.schemas.in.h:17
+msgid "GSM network APN"
+msgstr "GSM-Netzwerk APN"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "GSM network PIN"
+msgstr "GSM-Netzwerk PIN"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "GSM network PUK"
+msgstr "GSM-Netzwerk PUK"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "GSM network access point name configuration"
+msgstr "GSM-Netzwerk Namenseinstellung Zugriffspunkt"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "GSM network number"
+msgstr "GSM-Netzwerk Nummer"
+
+#: ../data/sugar.schemas.in.h:22
+msgid "GSM network password"
+msgstr "GSM-Netzwerk Passwort"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "GSM network password configuration"
+msgstr "GSM-Netzwerk Passworteinstellung"
+
+#: ../data/sugar.schemas.in.h:24
+msgid "GSM network personal identification number configuration"
+msgstr "GSM-Netzwerk PIN-Einstellung"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "GSM network personal unlock key configuration"
+msgstr "GSM-Netzwerk PUK-Einstellung"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "GSM network telephone number configuration"
+msgstr "GSM-Netzwerk Telefonnummereinstellung"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "GSM network username"
+msgstr "GSM-Netzwerk Benutzername"
+
+#: ../data/sugar.schemas.in.h:28
+msgid "GSM network username configuration"
+msgstr "GSM-Netzwerk Benutzernameneinstellung"
+
+#: ../data/sugar.schemas.in.h:29
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"Falls WAHR, wird Sugar es für andere Nutzer des Jabber-Servers zulassen, uns "
+"zu suchen."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "Falls WAHR, wird Sugar die Option \"Abmelden\" anzeigen."
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Jabber Server"
+msgstr "Jabber-Server"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "Keyboard layouts"
+msgstr "Tastaturlayouts"
+
+#: ../data/sugar.schemas.in.h:33
+msgid "Keyboard model"
+msgstr "Tastaturmodell"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Keyboard options"
+msgstr "Tastatureinstellungen"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Layout of the favorites view."
+msgstr "Layout der Favoriten-Ansicht."
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+"Liste der Tastaturlayouts. Jeder Eintrag sollte von der Form "
+"Layout(Variante) sein."
+
+#: ../data/sugar.schemas.in.h:37
+msgid "List of keyboard options."
+msgstr "Liste der Tastatureinstellungen."
+
+#: ../data/sugar.schemas.in.h:38
+msgid "Power Automatic"
+msgstr "Automatische Energieverwaltung"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "Power Automatic."
+msgstr "Automatische Energieverwaltung."
+
+# (Markus S.) war 'Extreme Energieverwaltung'
+#: ../data/sugar.schemas.in.h:40
+msgid "Power Extreme"
+msgstr "Extremes Energiesparen"
+
+# (Markus S.) war 'Extreme Energieverwaltung'
+#: ../data/sugar.schemas.in.h:41
+msgid "Power Extreme."
+msgstr "Extremes Energiesparen."
+
+#: ../data/sugar.schemas.in.h:42
+msgid "Publish to Gadget"
+msgstr "Veröffentlichen auf Gerät"
+
+#: ../data/sugar.schemas.in.h:43
+msgid "Setting for muting the sound device."
+msgstr "Einstellung zum Stummschalten der Audio-Ausgabe."
+
+#: ../data/sugar.schemas.in.h:44
+msgid "Show Log out"
+msgstr "Abmelden anzeigen"
+
+#: ../data/sugar.schemas.in.h:45
+msgid "Sound Muted"
+msgstr "Stummgeschaltet"
+
+#: ../data/sugar.schemas.in.h:46
+msgid "The keyboard model to be used"
+msgstr "Das zu verwendende Tastaturmodell"
+
+#: ../data/sugar.schemas.in.h:48
+msgid "Timezone setting for the system."
+msgstr "Zeitzoneneinstellung des Systems."
+
+#: ../data/sugar.schemas.in.h:49
+msgid "Url of the jabber server to use."
+msgstr "URL des zu nutzenden Jabber-Servers."
+
+#: ../data/sugar.schemas.in.h:50
+msgid "Url where the backup is saved to."
+msgstr "URL, unter der das Backup gespeichert wird."
+
+#: ../data/sugar.schemas.in.h:51
+msgid "User Color"
+msgstr "Benutzerfarbe"
+
+#: ../data/sugar.schemas.in.h:52
+msgid "User Name"
+msgstr "Benutzername"
+
+#: ../data/sugar.schemas.in.h:53
+msgid "User name that is used throughout the desktop."
+msgstr "Benutzername, der überall auf dem Desktop benutzt wird."
+
+#: ../data/sugar.schemas.in.h:54
+msgid "Volume Level"
+msgstr "Lautstärke"
+
+#: ../data/sugar.schemas.in.h:55
+msgid "Volume level for the sound device."
+msgstr "Lautstärkepegel für die Audio-Ausgabe."
+
+#: ../data/sugar.schemas.in.h:56
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"Im Wiederaufnahmemodus führt ein Anklicken des Favoriten-Symbols dazu, dass "
+"der letzte Eintrag für diese Aktivität fortgesetzt wird."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: WARNUNG, mehr als eine Auswahl mit dem gleichen Namen "
+"gefunden: %s module: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: Parameter=%s ist keine verfügbare Option"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+# (Markus S.) war 'Benutzung: sugar-control-panel [ option ] key [ args ... ] \n'; 'Parameter' war 'Key'.
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Benutzung: sugar-control-panel [ Option ] Parameter [ Argumente ... ] \n"
+" Einstellungen für Sugar. \n"
+" Optionen: \n"
+" -h Diese Hilfe anzeigen und beenden\n"
+" -l Alle verfügbaren Optionen auflisten\n"
+" -h Parameter Informationen zu diesem Parameter zeigen\n"
+" -g Parameter Den aktuellen Wert für diesen Parameter auslesen\n"
+" -s Parameter Den aktuellen Wert für diesen Parameter festlegen\n"
+" -c Parameter Den aktuellen Wert für diesen Parameter zurücksetzen\n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Um die Änderungen zu übernehmen, muss Sugar neu gestartet werden.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "Warnung"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Neustart zur Übernahme der Änderungen notwendig"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "Änderungen verwerfen"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Später"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "Jetzt neu starten"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "Fertig"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "Version %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "Löschen bestätigen"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Löschen bestätigen: Willst du %s wirklich dauerhaft löschen?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Behalten"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:106
+msgid "Erase"
+msgstr "Löschen"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "Favorit entfernen"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "Zum Favoriten machen"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Freie Form"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Ring"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Spirale"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Rechteck"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Dreieck"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "Anmeldung fehlgeschlagen"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "Anmeldung erfolgreich"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "Du bist nun an deinem Schulserver angemeldet."
+
+#: ../src/jarabe/desktop/favoritesview.py:631
+msgid "Register"
+msgstr "Am Schulserver anmelden"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Software-Aktualisierung"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"Aktualisiere deine Aktivitäten, um die Kompatibilität mit deiner neuen "
+"Software sicherzustellen."
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Jetzt prüfen"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Listenansicht"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Favoritenansicht"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "Schlüsseltyp:"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "Authentifizierungstyp:"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "WPA & WPA2 Personal"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "WLAN-Sicherheit:"
+
+#: ../src/jarabe/desktop/meshbox.py:491
+#, python-format
+msgid "Mesh Network %d"
+msgstr "Maschennetzwerk %d"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:628
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:66 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "Fortsetzen"
+
+#: ../src/jarabe/desktop/meshbox.py:633
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "Mitmachen"
+
+#: ../src/jarabe/desktop/schoolserver.py:104
+msgid "Cannot connect to the server."
+msgstr "Kann nicht mit dem Server verbinden."
+
+#: ../src/jarabe/desktop/schoolserver.py:109
+msgid "The server could not complete the request."
+msgstr "Der Server konnte die Anforderung nicht erfüllen."
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "Ablehnen"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "%s von %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "Übertragung von %r"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "Akzeptieren"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr "Verwerfen"
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "Übertragung zu %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "Entfernen"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "Öffnen"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "Öffnen mit"
+
+# (Markus S.) 'clipping', nicht 'clipped'
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s ausgeschnitten"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Umgebung"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "Klicken zum Wechseln der Farbe:"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Zurück"
+
+# (Markus S.) war 'Nächste'
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "Vor"
+
+#: ../src/jarabe/journal/expandedentry.py:151
+#: ../src/jarabe/journal/palettes.py:60
+msgid "Untitled"
+msgstr "Ohne Titel"
+
+#: ../src/jarabe/journal/expandedentry.py:242
+msgid "No preview"
+msgstr "Keine Vorschau"
+
+#: ../src/jarabe/journal/expandedentry.py:261
+#, python-format
+msgid "Kind: %s"
+msgstr "Art: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:261
+msgid "Unknown"
+msgstr "Unbekannt"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Date: %s"
+msgstr "Datum: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Size: %s"
+msgstr "Größe: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:285 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "Kein Datum"
+
+#: ../src/jarabe/journal/expandedentry.py:292
+msgid "Participants:"
+msgstr "Teilnehmer:"
+
+#: ../src/jarabe/journal/expandedentry.py:315
+msgid "Description:"
+msgstr "Beschreibung:"
+
+#: ../src/jarabe/journal/expandedentry.py:340
+msgid "Tags:"
+msgstr "Stichwörter:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Tagebuch"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Suchen"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "Beliebiges Datum"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Heute"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Seit gestern"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Vergangene Woche"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Vergangener Monat"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Vergangenes Jahr"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Alle"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Meine Freunde"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Meine Klasse"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Alles"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:84
+msgid "Copy"
+msgstr "Kopieren"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start"
+msgstr "Start"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "Dein Tagebuch ist leer."
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "Keine passenden Einträge"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "Suchfeld leeren"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Dein Tagebuch ist voll."
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"Lösche bitte einige alte Tagebucheinträge, um Platz für neue zu schaffen."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Tagebuch anzeigen"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Ein Objekt auswählen"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:310
+msgid "Close"
+msgstr "Schließen"
+
+#: ../src/jarabe/journal/palettes.py:67
+msgid "Resume with"
+msgstr "Fortsetzen mit"
+
+#: ../src/jarabe/journal/palettes.py:70
+msgid "Start with"
+msgstr "Beginnen mit"
+
+#: ../src/jarabe/journal/palettes.py:92
+msgid "Send to"
+msgstr "Senden an"
+
+#: ../src/jarabe/journal/palettes.py:101
+msgid "View Details"
+msgstr "Details betrachten"
+
+#: ../src/jarabe/journal/palettes.py:179
+msgid "No friends present"
+msgstr "Keine Freunde anwesend"
+
+#: ../src/jarabe/journal/palettes.py:184
+msgid "No valid connection found"
+msgstr "Keine gültige Verbindung gefunden"
+
+#: ../src/jarabe/journal/palettes.py:212
+msgid "No activity to resume entry"
+msgstr "Keine Aktivität, um den Eintrag fortzusetzen"
+
+#: ../src/jarabe/journal/palettes.py:214
+msgid "No activity to start entry"
+msgstr "Keine Aktivität, um den Eintrag zu beginnen"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Freund entfernen"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Freunde werden"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Rechner Ausschalten"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Benutzer Abmelden"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "Meine Einstellungen"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Einladen zu %s"
+
+#: ../src/jarabe/view/launcher.py:192
+#, python-format
+msgid "<b>%s</b> failed to start."
+msgstr "<b>%s</b> konnte nicht gestartet werden."
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Starte..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr "Quelltext betrachten"
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "Beenden"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr "Neu beginnen"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "Inhalte anzeigen"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB frei"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Quelltext der Instanz"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Quelltext"
+
+#: ../src/jarabe/view/viewsource.py:294
+msgid "Activity Bundle Source"
+msgstr "Quelltext des Aktivitätenbündels"
+
+#: ../src/jarabe/view/viewsource.py:301
+#, python-format
+msgid "View source: %r"
+msgstr "Quelltext betrachten: %r"
+
+#~ msgid "APN:"
+#~ msgstr "APN (Zugangspunkt):"
+
+#~ msgid "Title"
+#~ msgstr "Titel"
+
+#~ msgid "Version"
+#~ msgstr "Version"
+
+#~ msgid "Date"
+#~ msgstr "Datum"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "Notwendige Daten für die Registrierung sind nicht verfügbar."
+
+#~ msgid "Unmount"
+#~ msgstr "Einbindung lösen"
+
+#~ msgid "Restart"
+#~ msgstr "Neustart"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Verschlüsselungstyp:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid "Disconnecting..."
+#~ msgstr "Trenne Verbindung..."
+
+#~ msgid "About my XO"
+#~ msgstr "Über meinen XO"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Verbunden mit einem Schul-Maschennetzwerk-Portal"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Suche Schul-Maschennetzwerk-Portal..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Verbunden mit einem XO-Maschennetzwerk-Portal"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "Suche XO-Maschennetzwerk-Portal..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Verbunden mit einem einfachen Maschennetzwerk"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Starte ein einfaches Maschennetzwerk"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Unbekanntes Maschennetzwerk"
+
+#~ msgid "Settings"
+#~ msgstr "Einstellungen"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Zwischenablage-Objekt: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "Bitte einen Server angeben"
+
+# (Markus S.) war 'Kontrollfeld'
+#~ msgid "Control Panel"
+#~ msgstr "Kontrollleiste"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+# (Markus S.) Es geht offenbar um den Ring der gerade genutzten Aktivitäten unter Home
+#~ msgid "Ring view"
+#~ msgstr "Ringansicht"
+
+# (Markus S.) es scheint um den Ring der gerade genutzten Aktivitäten in Home zu gehen
+#~ msgid "Remove from ring"
+#~ msgstr "Aus dem Ring entfernen"
+
+#~ msgid "Add to ring"
+#~ msgstr "Zum Ring hinzufügen"
+
+#~ msgid "Changes require a sugar restart to take effect."
+#~ msgstr "Neustart von Sugar erforderlich, um die Änderungen zu übernehmen"
+
+#~ msgid "Changes require restart to take effect"
+#~ msgstr "Neustart erforderlich, um die Änderungen zu übernehmen"
+
+#~ msgid "Delay in milliseconds:"
+#~ msgstr "Verzögerung in Millisekunden:"
+
+#, fuzzy
+#~ msgid "Hot Corners"
+#~ msgstr "Heiße Ecken"
+
+#, fuzzy
+#~ msgid "Warm Edges"
+#~ msgstr "Warme Kanten"
+
+#~ msgid "off"
+#~ msgstr "Aus"
+
+#~ msgid "on"
+#~ msgstr "An"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "Zugriffsrechte notwendig. Du musst root sein für diese Aktion."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "Fehler beim Lesen der Zeitzone"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Fehler beim Kopieren der Zeitzone (von %s): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Änderung der Berechtigung für Zeitzone: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "Infos zu diesem XO"
+
+#~ msgid "Add to journal"
+#~ msgstr "Zum Journal hinzufügen"
+
+#~ msgid "Reboot"
+#~ msgstr "Neu starten"
+
+#~ msgid "My Battery life"
+#~ msgstr "Meine Akku-Laufzeit"
+
+#~ msgid "Battery charging"
+#~ msgstr "Akku wird geladen"
+
+#~ msgid "Battery discharging"
+#~ msgstr "Akku in Benutzung"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Akku vollständig geladen"
+
+#~ msgid "Invite"
+#~ msgstr "Einladen"
+
+#~ msgid "Text"
+#~ msgstr "Text"
+
+#~ msgid "Image"
+#~ msgstr "Bild"
+
+#~ msgid "Private"
+#~ msgstr "Privat"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "Meine Umgebung"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s Aktivität"
+
+# Alternative: Gemeinsam mit:
+#~ msgid "Share with:"
+#~ msgstr "Gemeinsam mit:"
+
+#~ msgid "Undo"
+#~ msgstr "Rückgängig"
+
+#~ msgid "Redo"
+#~ msgstr "Wiederholen"
+
+#~ msgid "Paste"
+#~ msgstr "Einfügen"
+
+#~ msgid "Keep error"
+#~ msgstr "Fehler beim Speichern"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "Fehler beim Speichern: Alle Änderungen gehen verloren"
+
+#~ msgid "Don't stop"
+#~ msgstr "Nicht stoppen"
+
+#~ msgid "Stop anyway"
+#~ msgstr "Trotzdem stoppen"
+
+#~ msgid "Continue"
+#~ msgstr "Weitermachen"
+
+#~ msgid "OK"
+#~ msgstr "OK"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d Jahr"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d Jahre"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d Monat"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d Monate"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d Woche"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d Wochen"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d Tag"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d Tage"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d Stunde"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d Stunden"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d Minute"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d Minuten"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d Sekunde"
+
+#~ msgid " and "
+#~ msgstr " und "
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid ", "
+#~ msgstr ", "
diff --git a/shell/po/dz.po b/shell/po/dz.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/dz.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/el.po b/shell/po/el.po
new file mode 100644
index 0000000..7980d12
--- /dev/null
+++ b/shell/po/el.po
@@ -0,0 +1,777 @@
+# Greek translation of Sugar.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Simos Xenitellis <simos.lists@googlemail.com>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: Sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-07-23 07:44-0400\n"
+"PO-Revision-Date: 2008-08-05 08:05-0400\n"
+"Last-Translator: Γιάννης Κασκαμανίδης <ttnfy17@yahoo.gr>\n"
+"Language-Team: Greek <olpc@grnet.gr>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "Όνομα:"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "Πατήστε για να αλλάξτε χρώμα:"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr "Πίσω"
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "Ολοκληρώθηκε"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "Επόμενο"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "Διαγραφή φίλου/ης"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "Να γίνει φίλος/η"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "Προσκάλεσε στο %s"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "Διαγραφή"
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "Άνοιγμα"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63 ../src/view/home/HomeBox.py:86
+msgid "Keep"
+msgstr "Διατήρησε"
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr "Άνοιγμα με"
+
+#: ../src/view/clipboardmenu.py:216
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Αντικείμενο προχείρου: %s."
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "Τύπος Κλειδιού"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "Τύπος Πιστοποίησης"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "Τύπος Κρυπτογράφησης"
+
+#: ../src/view/Shell.py:240
+msgid "Screenshot"
+msgstr "Στιγμιότυπο οθόνης"
+
+#: ../src/view/home/HomeBox.py:80
+msgid "Confirm erase"
+msgstr "Επιβεβαίωση διαγραφής"
+
+#: ../src/view/home/HomeBox.py:82
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Επιβεβαίωση διαγραφής: Θέλετε να διαγράψετε μόνιμα %s?"
+
+#: ../src/view/home/HomeBox.py:89 ../src/view/palettes.py:120
+msgid "Erase"
+msgstr "Διαγραφή"
+
+#: ../src/view/home/HomeBox.py:215
+msgid "List view"
+msgstr "Προβολή λίστας"
+
+#: ../src/view/home/HomeBox.py:216
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/view/home/HomeBox.py:273
+msgid "Favorites view"
+msgstr "Προβολή αγαπημένων"
+
+#: ../src/view/home/HomeBox.py:274
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:282
+msgid "Freeform"
+msgstr "Ελεύθερο σχήμα"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:289
+msgid "Ring"
+msgstr "Δακτύλιος"
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "Σύνδεση"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "Αποσύνδεση"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "Αποσύνδεση..."
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr "Σύνδεση..."
+
+# TODO: show the channel number
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr "Συνδέθηκε"
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr "Δίκτυο πλέγματος"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:119
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr "Αποσύνδεση..."
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:61
+msgid "Resume"
+msgstr "Συνέχιση"
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:205
+msgid "Join"
+msgstr "Σύνδεση"
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr "Η μπαταρία μου"
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr "Φόρτιση"
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr "Απομένει ελάχιστη ενέργεια"
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d απομένουν"
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr "Φορτισμένη"
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr "Τα ηχεία μου"
+
+#: ../src/view/devices/speaker.py:119
+msgid "Unmute"
+msgstr "Άρση σίγασης"
+
+#: ../src/view/devices/speaker.py:122
+msgid "Mute"
+msgstr "Σίγαση"
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr "Αποσυνδέθηκε"
+
+#: ../src/view/devices/network/wireless.py:137
+msgid "Channel"
+msgstr "Κανάλι"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "Γειτονιά"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "Ομάδα"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "Αρχή"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "Δραστηριότητα"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-πίνακας ελέγχου: Προειδοποίηση, βρέθηκαν περισσότερες από μία επιλογές "
+"με το ίδιο όνομα: %s άρθρωμα: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-πίνακας ελέγχου: κλειδί=%s μη διαθέσιμη επιλογή"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-πίνακας ελέγχου: %s"
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"Χρήση: sugar-πίνακας ελέγχου [ επιλογή ] κλειδί [ ορίσματα ... ] \n"
+"Έλεγχος περιβάλλοντος εργασίας sugar. \n"
+"Επιλογές: \n"
+"-h εμφάνιση αυτού του μηνύματος βοήθειας και έξοδος \n"
+"-l καταλογογράφηση όλων των διαθέσιμων επιλογών \n"
+"-h κλειδί εμφάνισης πληροφοριών γι' αυτό το κλειδί \n"
+"-g κλειδί που παίρνει την τρέχουσα τιμή του κλειδιού \n"
+"-s κλειδί που καθορίζει την τρέχουσα τιμή του κλειδιού \n"
+" "
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Για να εφαρμοστούν οι αλλαγές σου θα πρέπει να επανεκκινήσεις το sugar\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "Ακύρωση"
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:294
+msgid "Ok"
+msgstr "Οκ"
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:260
+msgid "Changes require restart"
+msgstr "Οι αλλαγές απαιτούν επανεκκίνηση"
+
+#: ../src/controlpanel/gui.py:259
+msgid "Warning"
+msgstr "Προειδοποίηση"
+
+#: ../src/controlpanel/gui.py:263
+msgid "Cancel changes"
+msgstr "Ακύρωση αλλαγών"
+
+#: ../src/controlpanel/gui.py:267
+msgid "Later"
+msgstr "Αργότερα"
+
+#: ../src/controlpanel/gui.py:271
+msgid "Restart now"
+msgstr "Επανεκκίνηση τώρα"
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr "Πρέπει να εισαχθεί ένα όνομα."
+
+#: ../src/controlpanel/model/aboutme.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "πινελιά: χρώμα=%s απόχρωση=%s"
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr "πινελιά: %s"
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "γέμισμα: χρώμα=%s απόχρωση=%s"
+
+#: ../src/controlpanel/model/aboutme.py:76
+#, python-format
+msgid "fill: %s"
+msgstr "γέμισμα: %s"
+
+#: ../src/controlpanel/model/aboutme.py:87
+msgid "Error in specified color modifiers."
+msgstr "Λάθος στους διαμορφωτές καθορισμένου χρώματος"
+
+#: ../src/controlpanel/model/aboutme.py:90
+msgid "Error in specified colors."
+msgstr "Λάθος στα καθορισμένα χρώματα"
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "Δεν είναι διαθέσιμο"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr "Λάθος η ζώνη ώρας δεν υπάρχει"
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr "Η τιμή πρέπει να είναι ακέραιος αριθμός."
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+"Δεν είναι δυνατή η πρόσβαση ~/.i18n. Δημιουργία προκαθορισμένων ρυθμίσεων."
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Γλώσσα για τον κωδικό=%s δεν μπορεί να καθοριστεί."
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Συγνώμη αλλά δεν μιλάω '%s'."
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr "Πρέπει να εισαχθεί ένα όνομα."
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr "Η κατάσταση είναι άγνωστη."
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+"Λάθος σε καθορισμένη παράμετρο κουμπιού επιλογής χρήση κλειστού/ανοικτού."
+
+#: ../src/controlpanel/model/power.py:57
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Σφάλμα στην αυτόματη παράμετρο pm, χρησιμοποιήστε το on/off."
+
+#: ../src/controlpanel/model/power.py:86
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Σφάλμα στην ακραία παράμετρο pm, χρησιμοποιήστε το on/off."
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr "Σχετικά με μένα"
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr "Πατήστε για να αλλάξετε χρώμα:"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr "Σχετικά με τον XO μου"
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr "Ταυτότητα"
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr "Σειριακός αριθμός:"
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr "Λογισμικό"
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr "Αναγνωριστικό έκδοσης:"
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr "Ημερομηνία & ώρα"
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr "Ζώνη ώρας"
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr "Πλαίσιο"
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr "ποτέ"
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr "στιγμιαίος"
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr "%s δεπτερόλεπτα"
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr "Καθυστέρηση ενεργοποίησης"
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr "Γωνία"
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr "Άκρη"
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr "Γλώσσα"
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr "Δίκτυο"
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr "Ασύρματο"
+
+#: ../src/controlpanel/view/network.py:61
+#, fuzzy
+msgid "Radio:"
+msgstr "Ραδιοκύματα:"
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr "Πλεγματοειδές δίκτυο"
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr "Διακομιστής:"
+
+#: ../src/controlpanel/view/power.py:27
+msgid "Power"
+msgstr "Ενέργεια"
+
+#: ../src/controlpanel/view/power.py:51
+msgid "Power management"
+msgstr "Διαχείριση ενέργειας"
+
+#: ../src/controlpanel/view/power.py:61
+msgid "Automatic power management (increases battery life)"
+msgstr "Αυτόματα διαχείριση ενέργειας (αυξάνει τη διάρκεια της μπαταρίας)"
+
+#: ../src/controlpanel/view/power.py:89
+msgid ""
+"Extreme power management (disables wireless radio, increases battery life)"
+msgstr ""
+"Ακραία διαχείριση ενέργειας (απενεργοποιεί το ασύρματο ραδιόφωνο, αυξάνει τη "
+"διάρκεια της μπαταρίας)"
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr "Συνδέθηκα σε μια Σχολική Πύλη Δικτυακού Πλέγματος"
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr "Αναζητώ μια Σχολική Πύλη Δικτυακού Πλέγματος..."
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr "Συνδέθηκα σε μια Πύλη Δικτυακού Πλέγματος XO"
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Αναζητώ μια Πύλη Δικτυακού Πλέγματος XO..."
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr "Συνδέθηκα σε ένα Απλό Δικτυακό Πλέγμα"
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr "Ξεκινώ ένα Απλό Δικτυακό Πλέγμα"
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr "Άγνωστο Δικτυακό Πλέγμα"
+
+#: ../src/view/frame/activitiestray.py:210
+#, fuzzy
+msgid "Decline"
+msgstr "Πτώση"
+
+#: ../src/view/home/favoritesview.py:285
+msgid "Registration Failed"
+msgstr "Η καταχώρηση απέτυχε"
+
+#: ../src/view/home/favoritesview.py:286
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/view/home/favoritesview.py:288
+msgid "Registration Successful"
+msgstr "Η καταχώρηση πέτυχε"
+
+#: ../src/view/home/favoritesview.py:289
+msgid "You are now registered with your school server."
+msgstr "Είστε καταχωρημένος στον διακομιστή του σχολείου."
+
+#: ../src/view/home/favoritesview.py:405
+msgid "Control Panel"
+msgstr "Πίνακας ελέγχου"
+
+#: ../src/view/home/favoritesview.py:416
+msgid "Restart"
+msgstr "Επανεκκίνηση"
+
+#: ../src/view/home/favoritesview.py:421
+msgid "Shutdown"
+msgstr "Τερματισμός"
+
+#: ../src/view/home/favoritesview.py:427
+msgid "Register"
+msgstr "Καταχώρηση"
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr "Εκκίνηση..."
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr "Διακοπή"
+
+#: ../src/view/palettes.py:104
+msgid "Start"
+msgstr "Έναρξη"
+
+#: ../src/view/palettes.py:132
+msgid "Remove favorite"
+msgstr "Αφαίρεση αγαπημένου"
+
+#: ../src/view/palettes.py:136
+msgid "Make favorite"
+msgstr "Δημιουργία αγαπημένου"
+
+#: ../src/view/palettes.py:185
+msgid "Show contents"
+msgstr "Προβολή περιεχομένων"
+
+#: ../src/view/palettes.py:209
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB ελεύθερα"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "Ring view"
+#~ msgstr "Προβολή δακτυλίου"
+
+#~ msgid "Remove from ring"
+#~ msgstr "Αφαίρεση από τον δακτύλιο"
+
+#~ msgid "Add to ring"
+#~ msgstr "Προσθήκη στον δακτύλιο"
+
+#~ msgid "Changes require a sugar restart to take effect."
+#~ msgstr ""
+#~ "Οι αλλαγές απαιτούν επανεκκίνηση του sugar προκειμένου να τεθούν σε ισχύ."
+
+#~ msgid "Changes require restart to take effect"
+#~ msgstr "Οι αλλαγές απαιτούν επανεκκίνηση προκειμένου να τεθούν σε ισχύ."
+
+#~ msgid "off"
+#~ msgstr "κλειστό"
+
+#~ msgid "on"
+#~ msgstr "ανοικτό"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr ""
+#~ "Δεν επιτρέπεται η πρόσβαση. Πρέπει να είσαι διαχειριστής για να τρέξεις αυτή "
+#~ "τη μέθοδο."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "Λάθος στην ανάγνωση της ζώνης ώρας"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Λάθος αντιγραφής ζώνης ώρας (από %s): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Άλλαξε την πρόσβαση της ζώνης ώρας: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "Σχετικά με αυτόν τον XO"
+
+#~ msgid "Add to journal"
+#~ msgstr "Προσθήκη στο χρονικό"
+
+#~ msgid "Reboot"
+#~ msgstr "Επανεκκίνηση"
+
+#~ msgid "My Battery life"
+#~ msgstr "Διάρκεια μπαταρίας"
+
+#~ msgid "Battery charging"
+#~ msgstr "Μπαταρία φορτίζει"
+
+#~ msgid "Battery discharging"
+#~ msgstr "Μπαταρία ξεφορτίζει"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Μπαταρία πλήρως φορτισμένη"
+
+#~ msgid "Invite"
+#~ msgstr "Πρόσκληση"
+
+#~ msgid "Text"
+#~ msgstr "Κείμενο"
+
+#~ msgid "Image"
+#~ msgstr "Εικόνα"
+
+#~ msgid "Share"
+#~ msgstr "Μοίρασε"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "Δραστηριότητα %s"
+
+#~ msgid "Share with:"
+#~ msgstr "Μοιράσου με:"
+
+#~ msgid "Private"
+#~ msgstr "Ιδιωτικό"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "Η Γειτονιά μου"
+
+#~ msgid "Undo"
+#~ msgstr "Αναίρεση"
+
+#~ msgid "Redo"
+#~ msgstr "Επανάληψη"
+
+#~ msgid "Copy"
+#~ msgstr "Αντιγραφή"
+
+#~ msgid "Paste"
+#~ msgstr "Επικόλληση"
+
+#~ msgid "Keep error"
+#~ msgstr "Λάθος διατήρησης"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "Λάθος διατήρησης: όλες οι αλλαγές θα χαθούν"
+
+#~ msgid "Don't stop"
+#~ msgstr "Μη σταματάς"
+
+#~ msgid "Stop anyway"
+#~ msgstr "Σταμάτα οπωσδήποτε"
+
+#~ msgid "Continue"
+#~ msgstr "Συνέχισε"
+
+#~ msgid "OK"
+#~ msgstr "ΟΚ"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d χρόνος"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d χρόνια"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d μήνας"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d μήνες"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d βδομάδα"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d βδομάδες"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d ημέρα"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d ημέρες"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d ώρα"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d ώρες"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d λεπτό"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d λεπτά"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d δεπτερόλεπτο"
+
+#~ msgid " and "
+#~ msgstr " και "
+
+#~ msgid ", "
+#~ msgstr ", "
diff --git a/shell/po/en.po b/shell/po/en.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/en.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/es.po b/shell/po/es.po
new file mode 100644
index 0000000..587608f
--- /dev/null
+++ b/shell/po/es.po
@@ -0,0 +1,1573 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: olpc-sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-09-05 00:31-0400\n"
+"PO-Revision-Date: 2010-01-18 19:18+0200\n"
+"Last-Translator: Chris <cjl@laptop.org>\n"
+"Language-Team: Fedora Spanish <fedora-trans-es@redhat.com>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 2.0.1\n"
+"X-Poedit-Language: Spanish\n"
+"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-Basepath: .\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Acerca de mí"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Debe ingresar un nombre."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "borde: color=%s tonalidad=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "borde: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "relleno: color=%s tonalidad=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "relleno: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Error en modificadores de color especificados."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Error en colores especificados."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "Nombre:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Clic para cambiar su color:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Acerca de mi computadora"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "No disponible"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Identidad"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Número de serie:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Software"
+
+# Por ahora..
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Ensamble:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Azúcar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "Firmware Wireless:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Licencia y Copyright"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Azucar es la interfaz gráfica de usuario que usted esta mirando. Azucar es "
+"software libre, cubierto bajo la licencia GNU Licencia Publica General, y "
+"esta invitado a cambiarla y/o distribuir copias bajo ciertas condiciones que "
+"se describen en ella."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Licencia completa:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Fecha y hora"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Error, zona horaria no existe."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr "Zona horaria"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Cuadro"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "El valor debe ser un número entero."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "nunca"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "instantáneo"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s segundos"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Retraso de activación"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Esquina"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Borde"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "Teclado"
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr "Modelo de teclado"
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr "Tecla(s) para cambiar el diseño"
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr "Diseño(s) de teclado"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Idioma"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+"No se puede acceder a ~/.i18n. Crear configuración internacional estándar."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "El lenguaje del código=%s no pudo ser determinado."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Lo siento, yo no hablo '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"Añade idiomas en el orden que prefieres. Si una traducción no se encuentra "
+"disponible, se usará la siguiente en la lista."
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Red"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Estado desconocido."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Error en argumento especificado de radio use on/off."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Error en argumento especificado use 0/1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Inalámbrica"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Apague la radio inalámbrica y ahorre vida de batería"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Radio"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "Descarte el historial de la red si tiene problemas de conexión"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Descarte historial de la red"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Colaboración"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"El servidor es equivalente al cuarto en el cual se esta; la gente en el "
+"mismo servidor podrá verse entre ellos, aun cuando no esten en la misma red."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Servidor:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Energía"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Error en argumento automático de pm, use on/off."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Error en argumento extremo de pm, use on/off."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Manejo de energía"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Manejo automático de energía (incrementa la vida de la batería)"
+
+# best translationfor now
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Manejo extremo de energía (deshabilita el radio wireless, incrementa la vida "
+"de la batería)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Actualización de Software"
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"Las actualizaciones de software corrigen errores, eliminan vulnerabilidades "
+"de seguridad y proveen nuevas características."
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr "Probando %s..."
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr "Descargando %s..."
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr "Actualizando %s..."
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr "Tu software esta actualizado"
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "Puedes instalar %s actualización"
+msgstr[1] "Puedes instalar %s actualizaciones"
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr "Buscando actualizaciones..."
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr "Instalando actualizaciones..."
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s actualización fue instalada"
+msgstr[1] "%s actualizaciones fueron instaladas"
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr "Instalación seleccionada"
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr "Tamaño de descarga: %s"
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "Desde la version %(current)d hacia %(new)s (Size: %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+msgid "None"
+msgstr "Ninguno"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr "1 KB"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f KB"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Mi batería"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Eliminado"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Cargando"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Queda muy poca batería"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "Quedan %(hour)d:%(min).2d"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Cargada"
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr "Direccion IP: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr "Desconectando..."
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr "Crear nueva red inalámbrica"
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:264
+msgid "Connecting..."
+msgstr "Conectando..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:270
+msgid "Connected"
+msgstr "Conectado"
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr "Canal"
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr "Red Cableada"
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr "Velocidad"
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr "%s's red %s"
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Mis parlantes"
+
+# la traducción la tome del AlsaMixer de Gnome.
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Dar voz"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Silenciar"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr "Malla"
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Grupo"
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Hogar"
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Actividad"
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr "Captura de pantalla"
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "Captura pantalla de \"%s\""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr "URL de Respaldo"
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"El color para el ícono del XO se utiliza en todo el escritorio. La cadena "
+"está compuesta por el trazo y color de relleno de color, el formato es el de "
+"colores RBG. Ejemplo: #AC32FF, #9A5200"
+
+# es la mejor traduccion ?
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr "Retraso de las Esquinas"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr "Retraso para la activación del cuadro utilizando las esquinas."
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Retraso para la activación del cuadro utilizando los bordes."
+
+# es la mejor traduccion ?
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr "Retraso del Borde"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr "Diseño de favoritos"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr "Modo de reanudar favoritos"
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"Si es TRUE, Azúcar habilitará que otros usuarios nos busquen en el servidor "
+"Jabber."
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "Si es TRUE, Azúcar mostrará una opción \"Terminar Sesión\"."
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr "Servidor Jabber"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr "Distribuciones del teclado"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr "Modelo del teclado"
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr "Opciones del teclado"
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr "Distribución de las actividades favoritas."
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+"Lista de las distribuciones de teclado. Cada entrada debe ser en la forma "
+"distribución(variante)"
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr "Lista de las opciones del teclado."
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr "Manejo automática de energía"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr "Manejo automática de energía."
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr "Manejo extremo de energía"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr "Manejo extremo de energía."
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr "Publicar en Gadget"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr "Configuración para silenciar el dispositivo de sonido."
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr "Mostrar Terminar Sesión"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr "Sonido silenciado"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr "El modelo del teclado que se utilizará"
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr "Configuración de zona horaria para el sistema."
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr "URL del servidor de Jabber para usar."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr "URL donde se guarda el backup."
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr "Color del usuario"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr "Nombre de usuario"
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr "Nombre de usuario que se utiliza en todo el escritorio."
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr "Nivel de volumen"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr "Nivel de volumen para el dispositivo de sonido."
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"Cuando en el modo de retomar, al hacer clic en un icono de favoritos causa "
+"que se retome la última entrada de esa actividad."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: ADVERTENCIA, hay más de una opción con el mismo nombre: "
+"módulo %s: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: clave=%s no es una opción disponible"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,<br /><br />
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Uso: sugar-control-panel [ opción ] clave [ args ... ] \n"
+" Control para el ambiente de sugar. \n"
+" Opciones: \n"
+" -h muestra este mensaje de ayuda y sale \n"
+" -l enumera todas las opciones disponibles \n"
+" -h clave muestra la información sobre esta clave \n"
+" -g clave obtiene el valor actual de la clave \n"
+" -s clave establece el valor actual de la clave \n"
+" -c clave vaciar el valor actual de la clave \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Para aplicar sus cambios tiene que reiniciar Azúcar.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr "Advertencia"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Los cambios requieren reiniciar"
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr "Cancelar cambios"
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Después"
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr "Reiniciar ahora"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "Hecho"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr "Título"
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr "Versión"
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr "Fecha"
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr "Versión %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr "Confirmar borrado"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Confirmar el borrado: ¿Quiere borrar %s de forma permanente?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Guardar"
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:407
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr "Borrar"
+
+#: ../src/jarabe/desktop/activitieslist.py:428
+msgid "Remove favorite"
+msgstr "Remover favorito"
+
+#: ../src/jarabe/desktop/activitieslist.py:432
+msgid "Make favorite"
+msgstr "Hacer favorito"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Forma libre"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Anillo"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Espiral"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Caja"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Triángulo"
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr "Registro fallido"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr "Registro exitoso"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr "Ahora estás registrado en el servidor de colegio."
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr "Registro"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Actualización de Software"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"Actualice sus actividades para asegurar compatibilidad con su nuevo software"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Pruebe ahora"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Vista en lista"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Vista de favoritos"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+# This is an encryption key type, not a keyboard key
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr "Tipo de clave:"
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr "Tipo de autenticación:"
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr "WPA y WPA2 Personal"
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr "Seguridad inalámbrica:"
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr "Conectar"
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr "Desconectar"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:466
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr "Retomar"
+
+#: ../src/jarabe/desktop/meshbox.py:471
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr "Unirse"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "No se puede conectar al servidor."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "El servidor no pudo completar el pedido."
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr "Rechazar"
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr "%s de %s"
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr "Transferencia desde %r"
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr "Aceptar"
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr "Descartar"
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr "Transferencia a %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:52 ../src/jarabe/view/palettes.py:218
+msgid "Remove"
+msgstr "Eliminar"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "Abrir"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "Abrir con"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "recorte de %s"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Vecindario"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "Clic para cambiar de color:"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Atrás"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "Siguiente"
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "Sin título"
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr "Sin vista previa"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr "Tipo: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr "Desconocido"
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr "Fecha: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr "Tamaño: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr "Sin fecha"
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr "Participantes:"
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr "Descripción:"
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr "Etiquetas:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Diario"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Buscar"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "Cualquier momento"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Hoy"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Desde ayer"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Última semana"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Último mes"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Último año"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Cualquiera"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Mis amigos"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Mi clase"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Cualquiera"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "Copiar"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr "Iniciar"
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr "Su diario está vacío"
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr "No hay entradas coincidentes"
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr "Limpiar búsqueda"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Su diario está vacío"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"Por favor borre las entradas viejas del diario para hacer espacio a las "
+"nuevas entradas."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Mostrar diario"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Escoja un objeto"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Cerrar"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr "Reiniciar con"
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr "Empezar con"
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr "Enviar a"
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr "Ver detalles"
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr "No hay amigos presentes"
+
+# tildes
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr "No se encontró una conexión válida"
+
+# tildes...
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr "No se encontró una actividad para retomar la entrada"
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr "No se encontró una actividad para iniciar la entrada"
+
+# "Eliminate friend"??? That's a bit harsh. Wouldn't "quitar amigo" be a better choice?--
+# agree but i preffer remover :). that verbe has the exact meaning we are looking on here.
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Remover amigo"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Agregar amigo"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Apagar"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Salir"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "Mis ajustes"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Invitar a %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Iniciando..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr "Ver fuente"
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr "Parar"
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr "Empezar nuevo"
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr "Mostrar contenidos"
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB libres"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Fuente de la instancia"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Fuente"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "Fuente del paquete de la actividad"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "Ver código fuente: %r"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "No se puede obtener datos necesarios para el registro"
+
+#~ msgid "Unmount"
+#~ msgstr "Desmontar"
+
+#~ msgid "Restart"
+#~ msgstr "Reiniciar"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; y Contribuyentes."
+
+#~ msgid "Document"
+#~ msgstr "Documento"
+
+#~ msgid "Resume by default"
+#~ msgstr "Continuar de forma predeterminada"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Tipo de Encriptación:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+# DjToXiC: It's a good point, however, I think you should communicate that bug to the developers, because we only have to translate. ;-) In my opinion, the translation is perfect (I'm Uruguaian).
+#~ msgid "Disconnecting..."
+#~ msgstr "Desconectando..."
+
+#~ msgid "Mesh Network"
+#~ msgstr "Red Malla"
+
+#~ msgid "Disconnected"
+#~ msgstr "Desconectado"
+
+#~ msgid "About my XO"
+#~ msgstr "Acerca de mi XO"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Conectado a un enlace escolar de red malla"
+
+# "portal malla de colegio", en Castellano de España suena fatal... ¿Realmente se quiere decir malla?
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Buscando un enlace escolar de red malla..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Conectado a un Portal Malla XO"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "Buscando un Portal Malla XO..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Conectado a una Red Malla Simple"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Empezando una Red Malla Simple"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Red Malla Desconocida"
+
+#~ msgid "Settings"
+#~ msgstr "Configuración "
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Objeto de portapapel: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "Debe ingresar un servidor"
+
+#~ msgid "Control Panel"
+#~ msgstr "Panel de Control"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#, fuzzy
+#~ msgid "Ring view"
+#~ msgstr "Vista de llamada"
+
+#~ msgid "Remove from ring"
+#~ msgstr "Eliminar del anillo"
+
+#~ msgid "Add to ring"
+#~ msgstr "Agregar al anillo"
+
+#~ msgid "Changes require a sugar restart to take effect."
+#~ msgstr "Los cambios requieren reiniciar sugar para ser efectivos."
+
+#~ msgid "Changes require restart to take effect"
+#~ msgstr "Los cambios requieren reiniciar para ser efectivos"
+
+#~ msgid "Delay in milliseconds:"
+#~ msgstr "Retraso en milisegundos:"
+
+#~ msgid "Hot Corners"
+#~ msgstr "Esquinas Activas"
+
+#~ msgid "Warm Edges"
+#~ msgstr "Bordes Activos"
+
+#~ msgid "off"
+#~ msgstr "apagado"
+
+#~ msgid "on"
+#~ msgstr "encendido"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "permiso denegado. Usted necesita ser root para ejecutar este método."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "Error en la lectura de la zona horaria"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Error copiando zona horaria (desde %s): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Cambiando permisos de zona horaria: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "Acerca de este XO"
+
+#~ msgid "Add to journal"
+#~ msgstr "Agregar al diario"
+
+#~ msgid "Reboot"
+#~ msgstr "Reiniciar"
+
+#~ msgid "My Battery life"
+#~ msgstr "Carga de mi batería"
+
+#~ msgid "Battery charging"
+#~ msgstr "Batería cargándose"
+
+#~ msgid "Battery discharging"
+#~ msgstr "Batería descargandose"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Batería totalmente cargada"
+
+#~ msgid "Invite"
+#~ msgstr "Invitar"
+
+#~ msgid "Text"
+#~ msgstr "Texto"
+
+#~ msgid "Image"
+#~ msgstr "Imagen"
+
+#~ msgid "Audio"
+#~ msgstr "Audio"
+
+#~ msgid "Video"
+#~ msgstr "Video"
+
+#~ msgid "Etoys project"
+#~ msgstr "Proyecto Etoys"
+
+#~ msgid "Link"
+#~ msgstr "Enlace"
+
+#~ msgid "Share with:"
+#~ msgstr "Compartir con:"
+
+#~ msgid "Private"
+#~ msgstr "Privado"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "Mi Vecindario"
+
+#~ msgid "Undo"
+#~ msgstr "Deshacer"
+
+#~ msgid "Redo"
+#~ msgstr "Rehacer"
+
+#~ msgid "Paste"
+#~ msgstr "Pegar"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "Actividad %s"
+
+#, python-format
+#~ msgid "Text snippet"
+#~ "Web Page"
+#~ "PDF file"
+#~ "MS Word file"
+#~ "RTF file"
+#~ "Abiword file"
+#~ "Squeak project"
+#~ "OpenOffice text file"
+#~ "Object"
+#~ "Pick a buddy picture"
+#~ "My Picture:"
+#~ "My Color:"
+#~ "Stop download"
+#~ "Close"
+#~ "No options"
+#~ "Send"
+#~ msgstr "Recorte de texto"
+#~ "Página web"
+#~ "Archivo PDF"
+#~ "Archivo MS-Word"
+#~ "Archivo RTF"
+#~ "Archivo Abiword"
+#~ "Proyecto de Squeak"
+#~ "Archivo de texto de OpenOffice"
+#~ "Objeto"
+#~ "Elegir la imagen de amigo"
+#~ "Mi imagen:"
+#~ "Mi color:"
+#~ "Interrumpir la bajada"
+#~ "Cerrar"
+#~ "Ninguna opción"
+#~ "Enviar"
+
+#~ msgid "Keep error"
+#~ msgstr "Error de guardado"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "Error de guardado: todos los cambios se perderán"
+
+#~ msgid "Don't stop"
+#~ msgstr "No detener"
+
+#~ msgid "Stop anyway"
+#~ msgstr "Detener de todas formas"
+
+#~ msgid "Continue"
+#~ msgstr "Continuar"
+
+#~ msgid "OK"
+#~ msgstr "OK"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d año"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d años"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d mes"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d meses"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d semana"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d semanas"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d día"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d días"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d hora"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d horas"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d minuto"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d minutos"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d segundo"
+
+#~ msgid " and "
+#~ msgstr " y "
+
+#~ msgid ", "
+#~ msgstr ", "
diff --git a/shell/po/fa.po b/shell/po/fa.po
new file mode 100644
index 0000000..08db87b
--- /dev/null
+++ b/shell/po/fa.po
@@ -0,0 +1,419 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2008-01-09 10:16+0000\n"
+"Last-Translator: Sohaib Obaidi <ebtihaj_obaidi@yahoo.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "نام:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "برای تبدیلی رنگ تیک کن:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "عقب"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "شد"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "بعدی"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "دوست را پاک کن"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "دوست بسازید"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "دعوت به ( ) %s"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "پاک کردن"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "باز کردن"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "به یادداشت اضافه کردن"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "شی در حافظه : %s"
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "نوعیت کلید:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "نوعیت تصدیق:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "نوعیت پنهانی کردن:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "در حال شروع شدن...."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "از سر گرفتن"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "توقف"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "عکس صفحه"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "دوباره چالان کردن"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "بند کردن"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "راجستر و ثبت کردن"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "منقطع شدن"
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "شبکه بافته شده"
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "پیوستن"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "دوام باطری من"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "باطری پر میشود"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "باطری خالی میشود"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "باطری کاملا پر ش"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "منقطع شد"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "کانال"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "همسایگی"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "گروه"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "خانه"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr " فعالیت"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "تقسیم با:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "شخصی"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "همسایگی من"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "نگه داشتن"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "نکن"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "تکرار کن"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "نقل بگیر"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "بچسپان"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s فعالیت"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "نگه داشتن اشتباه"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "نگه داشتن اشتباه: همه تغیرات از بین میروند"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "توقف نکن"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr "به هر طوری توقف کن"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "لغو کن"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "درست است."
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "جاری"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "درست است."
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d سال"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d سال ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d ماه"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d ماه ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d هفته"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d هفته ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d روز"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d روزها"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d ساعت"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d ساعت ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d دقیقه"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d دقایق"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d ثانیه"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d ثانیه ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr "_ و _"
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr "_ یا _"
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "برای اجرا نمودن تغیرات تان شما باید شوگر را دوباره چالان کنید\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "اشتباه در تعدیل کننده رنگ معین"
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "اشتباه د رنگ معین"
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "خاموش کردن"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "روشن کردن"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "حالان نامشخص هست"
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr "اشتباه دراستدلال معین از خاموش/روشن نمودن رادیو "
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr "تردید اجازه. شما برای راندن این روش باید ریشه کار باشید"
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "اشتباه در خواندن منطقه جغرافیایی ساعات"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "اشتباه در نقل برداری منطقه جغرافیایی ساعات (از %s): %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "تبدیلی اجازت منطقه جغرافیایی ساعات: %s"
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr "اشتباه منطقه جغرافیایی ساعات وجود ندارد"
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "دسترسی نمیتواند %s. زمینه معیاری بسازید"
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "زبان برای رمز=%s تعین نمی گردد"
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "ببخشید من سخن گفته نمیتوانم \"%s\""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "با مدخل تنیده مکتب وصل گردید"
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "در حال تلاش برای یک مدخل تنیده مکتب"
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "با مدخل تنیده XO وصل گردید"
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "در حال تلاش برای یک مدخل تنیده XO"
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "با یک بافته ساده وصل گردید"
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "در حال شروع یک بافته ساده"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "بافته نا مشخص"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/fa_AF.po b/shell/po/fa_AF.po
new file mode 100644
index 0000000..f285c64
--- /dev/null
+++ b/shell/po/fa_AF.po
@@ -0,0 +1,419 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2008-02-06 06:09-0500\n"
+"Last-Translator: Sohaib Obaidi <ebtihaj_obaidi@yahoo.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "نام:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "برای تبدیلی رنگ تیک کن:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "عقب"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "شد"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "بعدی"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "دوست را حذف کن"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "دوست بسازید"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "دعوت به %s"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "حذف کن"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "باز کن"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "به یادداشت اضافه کن"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "شیی تخته رسم : %s."
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "نوعیت کلید:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "نوعیت تصدیق:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "نوعیت پنهانی کردن:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "در حال شروع شدن..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "ادامه"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "توقف"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "عکس صفحه"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "راه اندازي مجدد"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "خاموش کردن"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "ثبت کردن"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "منقطع شدن..."
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "شبکه تنیده"
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "پیوستن"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "حیات باطری من"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "باطری در حال پرشدن"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "باطری در حال تخلیه"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "باطری کاملا پر شد"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "منقطع شد"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "کانال"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "همسایگی"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "گروه"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "خانه"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "فعالیت"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "تقسیم با:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "شخصی"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "همسایگی من"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "نگه داشتن"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "نکن"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "تکرار کن"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "نقل بگیر"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "بچسپان"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "فعالیت %s"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "خطا را نگه دار"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "خطا را نگه دار: همه تغیرات از بین خواهند رفت"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "توقف نکن"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr "به هر صورت توقف کن"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "لغو کن"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "درست است"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "جاری"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "OK"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d سال"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d سال"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d ماه"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d ماه"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d هفته"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d هفته ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d روز"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d روزها"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d ساعت"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d ساعت ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d دقیقه"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d دقیقه ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d ثانیه"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d ثانیه ها"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr " و "
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr "، "
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "برای اجرا نمودن تغیرات تان شما باید شکر را دوباره آغاز کنید.\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "خطا در تعدیل کننده رنگ معین."
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "خطا در رنگ معین."
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "خاموش"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "روشن"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "وضعیت نامشخص است."
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr "روشن یا خاموش بودن خطا در استدلال مشخص استعمال رادیویی."
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr "اجازه غير قابل دسترس هست. شما برای اجرای این طریقه باید ریشه باشید."
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "خطا در خوانش منطقه زمانی"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "خطا در خوانش منطقه زمانی (از %s): %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "در حال تغییر دادن اجازت منطقه زمانی: %s"
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr "خطای منطقه زمانی وجود ندارد."
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "به %s دسترسی نمی تواند. زمینه معیاریی بسازید."
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "زبان برای رمز=%s تعیین کرده نمیشود."
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "متأسفم من '%s' گفته نمیتوانم."
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "با مدخل تنیده مکتب وصل گردید"
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "در حال تلاش برای یک مدخل تنیده مکتب..."
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "با مدخل تنیده XO وصل گردید"
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "در حال تلاش برای یک مدخل تنیده XO..."
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "با یک شبکه تنیده ساده وصل گردید"
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "در حال شروع کردن یک شبکه تنیده ساده"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "شبکه تنیده نامشخص"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr "در مورد این XO"
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr "در دسترس نیست"
diff --git a/shell/po/ff.po b/shell/po/ff.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/ff.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/fil.po b/shell/po/fil.po
new file mode 100644
index 0000000..93c6b6e
--- /dev/null
+++ b/shell/po/fil.po
@@ -0,0 +1,958 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-31 00:30-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:26
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:59
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:68
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:90
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:99
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:114
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:130
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:145
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:168
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:176
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:183
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:195
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:19
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:32
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:56
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:64
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:77
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:93
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:102
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:115
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:123
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:133
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:56
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:153
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:40
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:104
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:109
+#: ../src/jarabe/desktop/meshbox.py:246
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:113
+#: ../extensions/deviceicon/network.py:166
+#: ../src/jarabe/desktop/meshbox.py:252
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:126
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:141
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:169
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:46
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:128
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:131
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:50
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:196
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:205
+#: ../src/jarabe/frame/zoomtoolbar.py:42
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:212
+msgid "Document"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:226
+#: ../src/jarabe/journal/objectchooser.py:141
+msgid "Close"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:272
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:273
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:276
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281 ../src/jarabe/desktop/homebox.py:113
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:111
+#: ../src/jarabe/frame/activitiestray.py:683
+#: ../src/jarabe/frame/activitiestray.py:762
+#: ../src/jarabe/frame/activitiestray.py:790
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:334
+msgid "Ok"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:114
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:196
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:341
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:408
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:449
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:329
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:666
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:67
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:69
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73 ../src/jarabe/frame/clipboardmenu.py:62
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:76
+#: ../src/jarabe/journal/journaltoolbox.py:357
+#: ../src/jarabe/journal/palettes.py:112 ../src/jarabe/view/palettes.py:127
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:106
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:107
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:116
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:233
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:234
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:296
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:297
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:304
+msgid "Resume by default"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:130
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:134
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:440
+#: ../src/jarabe/frame/activitiestray.py:707
+#: ../src/jarabe/journal/journaltoolbox.py:425
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:62
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:445
+#: ../src/jarabe/frame/activitiestray.py:221
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:18
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:35
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:40
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:226
+#: ../src/jarabe/frame/activitiestray.py:655
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:608
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:610
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:612
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:629
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:640
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:673
+#: ../src/jarabe/frame/activitiestray.py:780
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:751
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:47
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:36
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:38
+msgid "Group"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:40
+msgid "Home"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/collapsedentry.py:258
+#: ../src/jarabe/journal/expandedentry.py:159
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:205
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:224
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:247
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:273
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:65
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:124
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:141
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:271
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:347
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:75 ../src/jarabe/view/palettes.py:111
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:40
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:41
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:369
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:136
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:61
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:64
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:81
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:86
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:91
+msgid "Restart"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:96
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:131
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:43
+msgid "Starting..."
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:73
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:145
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:149
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:201
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:223 ../src/jarabe/view/palettes.py:272
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:248
+msgid "Unmount"
+msgstr ""
diff --git a/shell/po/fr.po b/shell/po/fr.po
new file mode 100644
index 0000000..caf42af
--- /dev/null
+++ b/shell/po/fr.po
@@ -0,0 +1,1619 @@
+# translation of sugar.po to french
+# Copyright (C) 2007 the Package Owner
+# This file is distributed under the same license as the sugar graphical shell package.
+# Samuel Bizien <samuel@bizien.info>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-11 00:32-0500\n"
+"PO-Revision-Date: 2010-08-08 11:26+0200\n"
+"Last-Translator: samy boutayeb <s.boutayeb@free.fr>\n"
+"Language-Team: French <traduc@traduc.org>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Pootle 2.0.3\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Moi"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Vous devez indiquer un nom."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "stroke: color=%s hue=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "stroke: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "fill: color=%s hue=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "fill: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Erreur dans les modificateurs de couleur spécifiés."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Erreur dans les couleurs spécifiées."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "Nom :"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Cliquer pour changer de couleur :"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Mon ordinateur"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Non disponible"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Identité"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Numéro de série :"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Logiciel"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Version :"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar :"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Micrologiciel :"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "Micrologiciel sans fil :"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Copyright et licence"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Sugar est l'interface graphique utilisateur que vous utilisez actuellement. "
+"Sugar est un logiciel libre couvert par la licence GNU/GPL (General Public "
+"License). Vous êtes autorisé à le modifier et/ou à en distribuer des copies "
+"aux conditions spécifiées."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Licence complète :"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Date & heure"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Erreur : le fuseau horaire n'existe pas."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:33
+msgid "Timezone"
+msgstr "Fuseau horaire"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Cadre"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "La valeur doit être un entier."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "jamais"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "immédiat"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s secondes"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Délai d'activation"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Coin"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Bord"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "Clavier"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "Modèle de clavier"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "Touche(s) de modification de la disposition"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "Disposition(s) du clavier"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Langue"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Accès impossible à ~/.i18n. Création de paramètres par défaut."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "La langue associée au code = %s n'a pas pu être déterminée."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Désolé je ne parle pas '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"Ajoutez des langues dans l'ordre souhaité. Si la traduction n'est pas "
+"disponible, la suivante dans la liste sera utilisée."
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr "Configuration du modem"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:90
+msgid "Username:"
+msgstr "Identifiant :"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:101
+msgid "Password:"
+msgstr "Mot de passe :"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:112
+msgid "Number:"
+msgstr "Numéro :"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:123
+msgid "APN:"
+msgstr "APN :"
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Réseau"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "État inconnu."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Argument 'radio' spécifié incorrect. Utiliser marche/arrêt."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Argument spécifié incorrect. Utiliser 0/1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Réseau sans fil"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Désactiver la radio sans fil pour prolonger la batterie"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Radio"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+"Ignorer l'historique du réseau si vous avez du mal à vous connecter au "
+"réseau"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Ignorer l'historique du réseau"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Collaboration"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"Le serveur est comparable à la pièce dans laquelle vous vous trouvez : les "
+"personnes présentes sur le même serveur pourront se voir même si elles ne se "
+"trouvent pas sur le même réseau."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Serveur :"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Alimentation"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Erreur dans l'argument gestion de l'alimentation automatique."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Erreur dans l'argument gestion de l'alimentation extrême."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Gestion de l'alimentation"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Gestion automatique de l'alimentation (prolonge la batterie)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Gestion extrême de l'alimentation (désactive la radio sans fil, prolonge la "
+"durée de vie de la batterie)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Mise à jour logicielle"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"Les mises à jour logicielles corrigent les erreurs, éliminent les failles de "
+"sécurité et apportent de nouvelles fonctionnalités."
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "Vérification de %s..."
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "Téléchargement de %s..."
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "Mise à jour de %s..."
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "Vos logiciels sont à jour"
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "Vous pouvez installer %s mise à jour"
+msgstr[1] "Vous pouvez installer %s mises à jour"
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "Vérification des mises à jour..."
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "Installation des mises à jour..."
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s mise à jour a été installée"
+msgstr[1] "%s mises à jour ont été installées"
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "Installer les activités sélectionnées"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "Taille du téléchargement : %s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "De la version %(current)d à %(new)s (taille : %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "Zéro"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1 Ko"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f Ko"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f Mo"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Ma batterie"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Retiré"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "En charge"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "La batterie est pratiquement déchargée"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d restantes"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Charge complète"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "Adresse IP : %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:111
+msgid "Disconnect..."
+msgstr "Déconnexion..."
+
+#: ../extensions/deviceicon/network.py:116
+msgid "Create new wireless network"
+msgstr "Créer un nouveau réseau sans fil"
+
+#: ../extensions/deviceicon/network.py:122
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/desktop/meshbox.py:248 ../src/jarabe/desktop/meshbox.py:537
+msgid "Connecting..."
+msgstr "Connexion..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:126
+#: ../extensions/deviceicon/network.py:198
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:254 ../src/jarabe/desktop/meshbox.py:543
+msgid "Connected"
+msgstr "Connecté"
+
+#: ../extensions/deviceicon/network.py:158
+msgid "Channel"
+msgstr "Canal"
+
+#: ../extensions/deviceicon/network.py:173
+msgid "Wired Network"
+msgstr "Réseau filaire"
+
+#: ../extensions/deviceicon/network.py:201
+msgid "Speed"
+msgstr "Vitesse"
+
+#: ../extensions/deviceicon/network.py:228
+msgid "Wireless modem"
+msgstr "Modem sans fil"
+
+#: ../extensions/deviceicon/network.py:276
+msgid "Please wait..."
+msgstr "Patienter..."
+
+#: ../extensions/deviceicon/network.py:279
+#: ../src/jarabe/desktop/meshbox.py:164 ../src/jarabe/desktop/meshbox.py:494
+msgid "Connect"
+msgstr "Connecter"
+
+#: ../extensions/deviceicon/network.py:280
+msgid "Disconnected"
+msgstr "Déconnecté"
+
+#: ../extensions/deviceicon/network.py:283
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "Annuler"
+
+#: ../extensions/deviceicon/network.py:287
+#: ../src/jarabe/desktop/meshbox.py:168
+msgid "Disconnect"
+msgstr "Déconnecter"
+
+#: ../extensions/deviceicon/network.py:530
+#, python-format
+msgid "%s's network"
+msgstr "Réseau %s"
+
+#: ../extensions/deviceicon/network.py:597
+#: ../extensions/deviceicon/network.py:656
+msgid "Mesh Network"
+msgstr "Réseau maillé"
+
+#: ../extensions/deviceicon/network.py:857
+#, python-format
+msgid "Data sent %d kb / received %d kb"
+msgstr "Données envoyées %d ko / reçues %d ko"
+
+#: ../extensions/deviceicon/network.py:868
+msgid "Connection time "
+msgstr "Durée de connexion"
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Haut-parleurs"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Activer le son"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Mettre en sourdine"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "Réseau maillé"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Groupe"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Accueil"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Activité"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "Capture d'écran"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "Capture d'écran de \"%s\""
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr ""
+"\"désactivé\" pour demander un pseudo lors de l'initialisation ; \"système\" "
+"pour réutiliser l'identifiant long du compte UNIX."
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Backup URL"
+msgstr "Sauvegarde de l'URL"
+
+#: ../data/sugar.schemas.in.h:3
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"Couleur du XO utilisée sur le Bureau. La chaîne indique la couleur du trait "
+"et du remplissage. Le format correspond aux couleurs RVB. Exemple : "
+"#AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Corner Delay"
+msgstr "Délai des coins"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Default font face"
+msgstr "Police par défaut"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font size"
+msgstr "Corps de la police par défaut"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default nick"
+msgstr "Pseudo par défaut"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Delay for the activation of the frame using the corners."
+msgstr "Délai d'activation du cadre à l'aide des coins."
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Délai d'activation du cadre à l'aide des bords."
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Edge Delay"
+msgstr "Délai des bords"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Favorites Layout"
+msgstr "Disposition favorite"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Favorites resume mode"
+msgstr "Mode de reprise favori"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Font face that is used throughout the desktop."
+msgstr "Police utilisée sur le bureau."
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Font size that is used throughout the desktop."
+msgstr "Corps de la police utilisée sur le bureau."
+
+#: ../data/sugar.schemas.in.h:15
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"Si VRAI, Sugar permettra aux autres utilisateurs du serveur Jabber de nous "
+"retrouver."
+
+#: ../data/sugar.schemas.in.h:16
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "Si VRAI, Sugar affichera une option \"Déconnexion\"."
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Jabber Server"
+msgstr "Serveur Jabber"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Keyboard layouts"
+msgstr "Dispositions du clavier"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Keyboard model"
+msgstr "Modèle de clavier"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Keyboard options"
+msgstr "Options du clavier"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Layout of the favorites view."
+msgstr "Disposition de la vue favorite."
+
+#: ../data/sugar.schemas.in.h:22
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+"Liste des dispositions de claviers. Chaque ligne doit avoir la forme "
+"disposition(variante)"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "List of keyboard options."
+msgstr "Liste des options de clavier."
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Power Automatic"
+msgstr "Alimentation automatique"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Power Automatic."
+msgstr "Alimentation automatique."
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Power Extreme"
+msgstr "Alimentation extrême"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Power Extreme."
+msgstr "Alimentation extrême."
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Publish to Gadget"
+msgstr "Publication vers Gadget"
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Setting for muting the sound device."
+msgstr "Configuration de la mise en sourdine du périphérique audio."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Show Log out"
+msgstr "Afficher Déconnexion"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Sound Muted"
+msgstr "Audio désactivé"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "The keyboard model to be used"
+msgstr "Modèle de clavier à utiliser"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Timezone setting for the system."
+msgstr "Configuration du fuseau horaire du système."
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Url of the jabber server to use."
+msgstr "URL du serveur Jabber à utiliser."
+
+#: ../data/sugar.schemas.in.h:36
+msgid "Url where the backup is saved to."
+msgstr "URL d'enregistrement de la sauvegarde."
+
+#: ../data/sugar.schemas.in.h:37
+msgid "User Color"
+msgstr "Couleurs de l'utilisateur"
+
+#: ../data/sugar.schemas.in.h:38
+msgid "User Name"
+msgstr "Nom de l'utilisateur"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "User name that is used throughout the desktop."
+msgstr "Nom identifiant l'utilisateur sur le bureau."
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Volume Level"
+msgstr "Niveau de volume"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Volume level for the sound device."
+msgstr "Niveau de volume du périphérique audio."
+
+#: ../data/sugar.schemas.in.h:42
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"Lorsque le mode reprise est activé, cliquez sur l'icône Favoris pour "
+"reprendre le dernier élément de cette activité."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: ATTENTION, plusieurs options avec un nom identique ont "
+"été trouvées : %s module: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s n'est pas une option disponible"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Usage: sugar-control-panel [ option ] clé [ args ... ] \n"
+" Contrôle de l'environnement sugar. \n"
+" Options: \n"
+" -h afficher ce message d'aide et quitter \n"
+" -l afficher la liste des options disponibles \n"
+" -h clé afficher les informations sur cette clé \n"
+" -g clé obtenir la valeur actuelle associée à cette clé \n"
+" -s clé définir la valeur actuelle de cette clé \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Redémarrer sugar pour que les changements prennent effet.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "Attention"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Relancer pour valider"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "Abandonner"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Plus tard"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "Maintenant"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "Accepter"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "Version %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "Confirmer la suppression"
+
+# Conformer la suppression : faut-il supprimer %s définitivement ?
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Confirmer la suppression : faut-il supprimer %s définitivement ?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Conserver"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:105
+msgid "Erase"
+msgstr "Supprimer"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "Retirer le favori"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "Ajouter aux favoris"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Libre"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Concentrique"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Spirale"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Boîte"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Triangle"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "Echec de l'enregistrement"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "Enregistrement réussi"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "Vous êtes maintenant enregistré sur le serveur de l'école."
+
+#: ../src/jarabe/desktop/favoritesview.py:630
+msgid "Register"
+msgstr "S'enregistrer"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Mise à jour logicielle"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "Actualiser les activités pour assurer la compatibilité logicielle"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Vérifier maintenant"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Écran liste"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Écran favoris"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "Type de clé :"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "Type d'authentification :"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "WPA & WPA2 Personal"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "Sécurité sans fil :"
+
+#: ../src/jarabe/desktop/meshbox.py:492
+#, python-format
+msgid "Mesh Network %d"
+msgstr "Réseau maillé %d"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:629
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:65 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "Reprendre"
+
+#: ../src/jarabe/desktop/meshbox.py:634
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "Rejoindre"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "Impossible de se connecter au serveur."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "Le serveur n'a pas pu achever la requête."
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "Refuser"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%do"
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%dKo"
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%dMo"
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "%s sur %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "Transfert depuis %r"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "Accepter"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr "Refuser"
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "Transfert vers %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "Retirer"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "Ouvrir"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "Ouvrir avec"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s coupure"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Voisinage"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "Cliquer pour changer de couleur :"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Précédent"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "Suivant"
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:59
+msgid "Untitled"
+msgstr "Sans titre"
+
+#: ../src/jarabe/journal/expandedentry.py:243
+msgid "No preview"
+msgstr "Pas de prévisualisation"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Kind: %s"
+msgstr "Variante : %s"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+msgid "Unknown"
+msgstr "Inconnu"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Date: %s"
+msgstr "Date : %s"
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Size: %s"
+msgstr "Taille : %s"
+
+#: ../src/jarabe/journal/expandedentry.py:286 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "Sans date"
+
+#: ../src/jarabe/journal/expandedentry.py:293
+msgid "Participants:"
+msgstr "Participants :"
+
+#: ../src/jarabe/journal/expandedentry.py:316
+msgid "Description:"
+msgstr "Description :"
+
+#: ../src/jarabe/journal/expandedentry.py:341
+msgid "Tags:"
+msgstr "Étiquettes :"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Journal"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Rechercher"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "N'importe quand"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Aujourd'hui"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Depuis hier"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Depuis une semaine"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Depuis un mois"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Depuis une année"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Tout le monde"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Mes amis"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Ma classe"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Tout"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:83
+msgid "Copy"
+msgstr "Copier"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:68
+msgid "Start"
+msgstr "Lancer"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "Le journal est vide"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "Aucune entrée correspondante"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "Effacer la recherche"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Votre journal est plein"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"Effacer des entrées anciennes du Journal pour libérer de la place pour les "
+"nouvelles entrées."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Montre le Journal"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Choisir un objet"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Fermer"
+
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Resume with"
+msgstr "Reprendre avec"
+
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start with"
+msgstr "Commencer avec"
+
+#: ../src/jarabe/journal/palettes.py:91
+msgid "Send to"
+msgstr "Envoyer à"
+
+#: ../src/jarabe/journal/palettes.py:100
+msgid "View Details"
+msgstr "Afficher les détails"
+
+#: ../src/jarabe/journal/palettes.py:178
+msgid "No friends present"
+msgstr "Aucun ami présent"
+
+#: ../src/jarabe/journal/palettes.py:183
+msgid "No valid connection found"
+msgstr "Aucune connexion valide trouvée"
+
+#: ../src/jarabe/journal/palettes.py:211
+msgid "No activity to resume entry"
+msgstr "Aucune activité pour reprendre l'entrée"
+
+#: ../src/jarabe/journal/palettes.py:213
+msgid "No activity to start entry"
+msgstr "Acune activité pour démarrer l'entrée"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Retirer de mes amis"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Ajouter à mes amis"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Éteindre"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Se déconnecter"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "Mes paramètres"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Inviter à %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Démarrage..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr "Afficher la source"
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "Arrêter"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr "Commencer un nouveau"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "Afficher les contenus"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d Mo de libre"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Instancie source"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Source"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "Source du paquet activité"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "Afficher le code source : %r"
+
+#~ msgid "Title"
+#~ msgstr "Titre"
+
+#~ msgid "Version"
+#~ msgstr "Version"
+
+#~ msgid "Date"
+#~ msgstr "Date"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "Impossible d'obtenir les données nécessaires à l'enregistrement."
+
+#~ msgid "Unmount"
+#~ msgstr "Démonter"
+
+#~ msgid "Restart"
+#~ msgstr "Redémarrer"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008 One Laptop per Child Association Inc ; Red Hat Inc ; et "
+#~ "contributeurs."
+
+#~ msgid "Document"
+#~ msgstr "Document"
+
+#~ msgid "Resume by default"
+#~ msgstr "Reprise par défaut"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Type d'encryptage :"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid "Disconnecting..."
+#~ msgstr "Déconnexion..."
+
+#~ msgid "About my XO"
+#~ msgstr "Mon XO"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Connecté au portail du réseau maillé d'école"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Recherche un portail de réseau maillé d'école..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Connecté au portail de réseau maillé de XO"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "Recherche un portail de réseau maillé de XO..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Connecté à un réseau maillé simple"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Démarre un réseau maillé simple"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Réseau maillé inconnu"
+
+#~ msgid "Settings"
+#~ msgstr "Configuration"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Objet dans le presse-papier : %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "Vous devez indiquer un serveur."
+
+#~ msgid "Control Panel"
+#~ msgstr "Panneau de contrôle"
+
+#~ msgid "© 2008 One Laptop per Child Assocation "
+#~ msgstr "© 2008 One Laptop per Child Assocation "
+
+#, fuzzy
+#~ msgid "Sugar is the graphical user interface that "
+#~ msgstr "Sugar est l'interface utilisateur graphique que"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "Ring view"
+#~ msgstr "Vue concentrique"
+
+#, fuzzy
+#~ msgid "Remove from ring"
+#~ msgstr "Retirer de l'anneau"
+
+#~ msgid "Add to ring"
+#~ msgstr "Ajouter à l'anneau"
+
+#~ msgid "Changes require a sugar restart to take effect."
+#~ msgstr "Pour appliquer les changements, sugar doit être redémarré."
+
+#~ msgid "Changes require restart to take effect"
+#~ msgstr "Redémarrer pour appliquer les changements"
+
+#~ msgid "Delay in milliseconds:"
+#~ msgstr "Délai en millisecondes :"
+
+#, fuzzy
+#~ msgid "Hot Corners"
+#~ msgstr "Coins activables"
+
+#, fuzzy
+#~ msgid "Warm Edges"
+#~ msgstr "Bords dynamiques"
+
+#~ msgid "off"
+#~ msgstr "arrêt"
+
+#~ msgid "on"
+#~ msgstr "marche"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr ""
+#~ "Permission refusée. Vous devez être administrateur afin de lancer cette "
+#~ "méthode."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "Erreur de lecture de la zone temporelle"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Erreur en copiant la zone temporelle (de %s): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Changement de la permission de zone temporelle : %s"
+
+#~ msgid "About this XO"
+#~ msgstr "Information sur ce XO"
+
+#~ msgid "Add to journal"
+#~ msgstr "Ajouter au journal"
+
+#~ msgid "Reboot"
+#~ msgstr "Redémarrer"
+
+#~ msgid "My Battery life"
+#~ msgstr "Charge de la batterie"
+
+#~ msgid "Battery charging"
+#~ msgstr "Batterie en charge"
+
+#~ msgid "Battery discharging"
+#~ msgstr "Batterie en décharge"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Batterie chargée"
+
+#~ msgid "Pick a buddy picture"
+#~ msgstr "Choisir un avatar XO"
+
+#~ msgid "My Picture:"
+#~ msgstr "Ma photo :"
+
+#~ msgid "My Name:"
+#~ msgstr "Mon surnom :"
+
+#~ msgid "My Color:"
+#~ msgstr "Ma couleur :"
+
+#~ msgid "Invite"
+#~ msgstr "Inviter"
+
+#~ msgid "Stop download"
+#~ msgstr "Arrêter de télécharger"
+
+#~ msgid "Text"
+#~ msgstr "Texte"
+
+#~ msgid "Image"
+#~ msgstr "Image"
+
+#~ msgid "Save"
+#~ msgstr "Enregistrer"
+
+#~ msgid "Share"
+#~ msgstr "Partager"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "Activité %s"
+
+#~ msgid "Share with:"
+#~ msgstr "Partager avec :"
+
+#~ msgid "Private"
+#~ msgstr "Privé"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "Mon voisinage"
+
+#~ msgid "Undo"
+#~ msgstr "Annuler"
+
+#~ msgid "Redo"
+#~ msgstr "Répéter"
+
+#~ msgid "Paste"
+#~ msgstr "Coller"
+
+#~ msgid "Keep error"
+#~ msgstr "Conserver l'erreur"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "Conserver l'erreur : tous les changements seront perdus"
+
+#~ msgid "Don't stop"
+#~ msgstr "Ne pas arrêter"
+
+#~ msgid "Stop anyway"
+#~ msgstr "Arrêter malgré tout"
+
+#~ msgid "Continue"
+#~ msgstr "Continuer"
+
+#~ msgid "OK"
+#~ msgstr "OK"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d an"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d ans"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d mois"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d mois"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d semaine"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d semaines"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d jour"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d jours"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d heure"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d heures"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d minute"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d minutes"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d seconde"
+
+#~ msgid " and "
+#~ msgstr "_et_"
+
+#~ msgid ", "
+#~ msgstr ", "
diff --git a/shell/po/gu.po b/shell/po/gu.po
new file mode 100644
index 0000000..baf1787
--- /dev/null
+++ b/shell/po/gu.po
@@ -0,0 +1,365 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-02-09 00:30-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../src/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../src/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/home/activitiesdonut.py:104 ../src/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/activitiesdonut.py:111
+msgid "Stop"
+msgstr ""
+
+#: ../src/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:175 ../src/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../src/view/home/MeshBox.py:90 ../src/view/home/MeshBox.py:197
+#: ../src/view/devices/network/wireless.py:113
+#: ../src/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:195 ../src/view/devices/network/mesh.py:37
+#: ../src/view/devices/network/mesh.py:62
+#: ../src/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../src/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../src/controlpanel/control.py:219
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/control.py:273
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/control.py:276
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/control.py:312
+msgid "off"
+msgstr ""
+
+#: ../src/controlpanel/control.py:314
+msgid "on"
+msgstr ""
+
+#: ../src/controlpanel/control.py:316
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/control.py:336
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/control.py:340
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../src/controlpanel/control.py:370
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../src/controlpanel/control.py:401
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../src/controlpanel/control.py:406
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../src/controlpanel/control.py:416
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/control.py:421 ../src/controlpanel/control.py:440
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/control.py:467
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/control.py:477
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:27
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:55 ../src/controlpanel/cmd.py:67
+#: ../src/controlpanel/cmd.py:74
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:80
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
diff --git a/shell/po/ha.po b/shell/po/ha.po
new file mode 100644
index 0000000..53ad5cf
--- /dev/null
+++ b/shell/po/ha.po
@@ -0,0 +1,447 @@
+# translation of sugar.po to hausa
+# This file is distributed under the same license as the PACKAGE package.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER.
+# saudat mohammed <saudat@wazobialinux>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2006-07-10 16:37+0100\n"
+"Last-Translator: saudat mohammed <saudat@wazobialinux>\n"
+"Language-Team: hausa\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#: ../shell/PresenceWindow.py:62
+msgid "Who's around:"
+msgstr "Wa ke nan:"
+
+#: ../shell/PresenceWindow.py:104
+msgid "Share"
+msgstr "Raba"
+
+#: ../shell/StartPage.py:189
+msgid "Search"
+msgstr "Yi Bincike"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Baya"
+
+#: ../activities/browser/NavigationToolbar.py:23
+msgid "Forward"
+msgstr "Tura"
+
+#: ../activities/browser/NavigationToolbar.py:29
+msgid "Reload"
+msgstr "Sake Lodi"
+
+#: ../shell/shell.py:333
+msgid "Everyone"
+msgstr "Kowa"
+
+#: ../sugar/chat/ChatEditor.py:43
+msgid "Send"
+msgstr "Aika"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/he.po b/shell/po/he.po
new file mode 100644
index 0000000..63d4e34
--- /dev/null
+++ b/shell/po/he.po
@@ -0,0 +1,764 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-25 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/window.py:93 ../src/controlpanel/aboutme/view.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/window.py:125
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/window.py:175 ../src/journal/detailview.py:119
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/window.py:189 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/window.py:192
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:60
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:63
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:92
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:51
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:56 ../src/view/clipboardmenu.py:78
+msgid "Open"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:61 ../src/view/home/HomeBox.py:84
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:83
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:228
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:17
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:31
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:36
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/view/Shell.py:251
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:78
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:80
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:87 ../src/view/palettes.py:120
+#: ../src/journal/journaltoolbox.py:335 ../src/journal/palettes.py:75
+msgid "Erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:117
+msgid "Software Update"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:118
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:122 ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:124 ../src/controlpanel/gui.py:273
+msgid "Later"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:127
+msgid "Check now"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:261
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:262
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:320
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:321
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:159
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:166
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:218 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:221 ../src/view/devices/network/wireless.py:125
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/view/home/MeshBox.py:309 ../src/view/palettes.py:61
+#: ../src/journal/journaltoolbox.py:399 ../src/journal/palettes.py:57
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:314 ../src/view/frame/activitiestray.py:206
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:125
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:128
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:143
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/controlpanel/cmd.py:35
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:48
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:305
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:42 ../src/controlpanel/gui.py:265
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:264
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:268
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:277
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:76
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:87
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:90
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:32
+#: ../src/controlpanel/aboutme/__init__.py:22
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/model.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:55
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:64
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:87
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:96
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:111
+msgid "Sugar:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:126
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:148
+msgid "Copyright and License"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:156
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:163
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:175
+msgid "Full license:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/__init__.py:21
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/datetime/model.py:89
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/datetime/view.py:68
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/frame/model.py:38 ../src/controlpanel/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:114
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:131
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/language/view.py:70
+#: ../src/controlpanel/language/__init__.py:21
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:62
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:82
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:28
+#: ../src/controlpanel/network/__init__.py:21
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:54
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:62
+msgid "Turn of the wireless radio to save battery life"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:75
+msgid "Radio"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:91
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:100
+msgid "Discard network history"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:113
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:122
+msgid "Server:"
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:55
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:84
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:211
+msgid "Decline"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:107
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:189
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:401
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:442
+msgid "Triangle"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:295
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:296
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:298
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:299
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:420
+msgid "Settings"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:425
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:430
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:436
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/view/palettes.py:104 ../src/journal/journaltoolbox.py:402
+#: ../src/journal/palettes.py:59
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:138
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:142
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:191
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:215
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:62
+msgid "Search"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:119
+msgid "Anytime"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:121
+msgid "Today"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:123
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/journal/journaltoolbox.py:125
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/journal/journaltoolbox.py:127
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/journal/journaltoolbox.py:129
+msgid "Past year"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:136
+msgid "Anyone"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:138
+msgid "My friends"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:139
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/journal/journaltoolbox.py:255
+msgid "Anything"
+msgstr ""
+
+#. TODO: Add "Start with" menu item
+#: ../src/journal/journaltoolbox.py:325 ../src/journal/palettes.py:67
+msgid "Copy"
+msgstr ""
+
+#: ../src/journal/collapsedentry.py:248 ../src/journal/expandedentry.py:176
+#: ../src/journal/palettes.py:51
+msgid "Untitled"
+msgstr ""
+
+#: ../src/journal/journalactivity.py:119 ../src/journal/volumesmanager.py:57
+msgid "Journal"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:222
+msgid "No preview"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:241
+msgid "Participants:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:266
+msgid "Description:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:292
+msgid "Tags:"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:134
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:139
+msgid "Close"
+msgstr ""
+
+#: ../src/journal/volumestoolbar.py:93
+msgid "Unmount"
+msgstr ""
+
+#: ../src/journal/misc.py:95
+msgid "No date"
+msgstr ""
+
+#: ../src/journal/listview.py:39
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/journal/listview.py:40
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/journal/modalalert.py:59
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/journal/modalalert.py:63
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/journal/modalalert.py:75
+msgid "Show Journal"
+msgstr ""
diff --git a/shell/po/hi.po b/shell/po/hi.po
new file mode 100644
index 0000000..522ddc9
--- /dev/null
+++ b/shell/po/hi.po
@@ -0,0 +1,1416 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-11 00:32-0500\n"
+"PO-Revision-Date: 2008-04-11 03:32-0400\n"
+"Last-Translator: Prashant Thakkar <prashantbthakkar@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "मेरे बारे में"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "आपको एक नाम प्रविष्ट करना होगा."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "स्ट्रोक: रंग=%s वर्ण=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "स्ट्रोक: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "भरें: रंग=%s वर्ण=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "भरें: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr " दिए गये रंगरूपांतर के वर्णन मे ग़लती है"
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr " दिए गये रंगो के वर्णन मे ग़लती है"
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "नाम"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "रंग बदलने हेतु क्लिक करें:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "मेरे कम्प्यूटर के बारे में"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "उपलब्ध नही है"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "पहचान"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "सरल क्रमांक:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "सॉफ्टवेयर"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "बिल्ड:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "सुगर:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "फर्मवेयर:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "वायरलेस फर्मवेयर:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "सर्वाधिकार तथा लाइसेंस"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"आप जिसे देख रहे हैं वो ग्राफ़िकल यूजर इंटरफेस - सुगर है. सुगर मुफ़्त "
+"सॉफ़्टवेयर है, और इसे ग्नू - जनरल पब्लिक लाइसेंस के तहत जारी किया गया है, और "
+"लाइसेंस में दिए गए कुछ विशेष शर्तों के अधीन आप इसमें परिवर्तन करने या इसकी "
+"प्रति बनाकर वितरण करने के लिए आपका स्वागत है."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "पूरा लाइसेंस:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "तारीख़ व समय"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "गलती: समयक्षेत्र मौजूद नही है"
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:33
+msgid "Timezone"
+msgstr "समयक्षेत्र"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "ढांचा"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "मूल्य पूर्णांक में होना चाहिए."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "कभी नहीं"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "तत्काल"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s सेकंड"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "सक्रियण देरी"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "किनारा"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "किनारा"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "कुंजीपट"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "कुंजीपट मॉडल"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "खाका बदलने के लिए कुंजियाँ"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "कुंजीपट खाका"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "भाषा"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr " ~/.i18n पर पहुँच नहीं सका. मानक सेटिंग बनाएँ"
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "कूट की भाषा = %s अग्यात है"
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "माफ़ कीजिए , मैं %s नही बोलता"
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"जिस अनुक्रम में आप चाहते हैं, उसमें भाषाएँ जोड़ें. यदि अनुवाद उपलब्ध नहीं "
+"होगा, तो सूची में दिए गए अगले वाले को प्रयोग में लिया जाएगा."
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/view.py:90
+msgid "Username:"
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/view.py:101
+msgid "Password:"
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/view.py:112
+msgid "Number:"
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/view.py:123
+msgid "APN:"
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "नेटवर्क"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "स्थिति अज्ञात है"
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "दिए गये रेडियो तर्क मे ग़लती है ,बंद/चालू का वापर करे"
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "निर्दिष्ट तर्क प्रयोग 0/1 में त्रुटि है."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "वायरलेस"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "बैटरी का जीवन बढ़ाने के लिए वायरलेस रेडियो को बन्द कर दें"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "रेडियो"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+"यदि आपको नेटवर्क में कनेक्ट करने में समस्या हो रही है तो नेटवर्क इतिहास को "
+"मिटा दें."
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "नेटवर्क इतिहास मिटाएँ"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "साझेदारी"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"सर्वर को आपके कमरे के रुप में, जहाँ आप हैं, माना जा सकता है. एक ही सर्वर के "
+"लोग आपस में एक दूसरे को देख सकेंगे, भले ही वो एक ही नेटवर्क में न हों."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "सर्वर:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "पावर"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "स्वचालित पीएम तर्क में त्रुटि है, चालू/बन्द प्रयोग करें."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "एक्सट्रीम पीएम तर्क में त्रुटि है, चालू/बन्द प्रयोग करें."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "बिज़ली प्रबंधन"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "स्वचालित बिजली प्रबंधन (बैटरी का जीवन बढ़ाता है)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"एक्सट्रीम ऊर्जा प्रबंधन (वायरलेस रेडियो को बन्द करता है, बैटरी का जीवन "
+"बढ़ाने के लिए)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "सॉफ़्टवेयर अद्यतन"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"सॉफ़्टवेयर अपडेट में त्रुटियाँ दूर होती हैं, सुरक्षा समस्याओं से छुटकारा "
+"मिलता है तथा नई विशेषताएँ मिलती हैं."
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "%s जाँचा जा रहा है..."
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "%s डाउनलोड किया जा रहा है..."
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "%s अद्यतन किया जा रहा है..."
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "आपका सॉफ़्टवेयर अद्यतन है"
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "आप %s अद्यतन संस्थापित कर सकते हैं"
+msgstr[1] "आप %s अद्यतन संस्थापित कर सकते हैं"
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "अद्यतन के लिए जाँचा जा रहा है..."
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "अद्यतनों को संस्थापित किया जा रहा है..."
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s अद्यतन संस्थापित किया गया"
+msgstr[1] "%s अद्यतनों को संस्थापित किया गया"
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "चयनित को संस्थापित करें"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "डाउनलोड आकार: %s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "संस्करण %(current)d से %(new)s (आकार: %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "कुछ नहीं"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1कि.बा."
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f कि.बा."
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f मे.बा."
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "मेरी बैटरी"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "हटा दिया गया"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "चार्जिंग में"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "बहुत कम पावर बचा है"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d बाकी"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "चार्ज है"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "आईपी पता: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:111
+msgid "Disconnect..."
+msgstr " सम्पर्क तोडे"
+
+#: ../extensions/deviceicon/network.py:116
+msgid "Create new wireless network"
+msgstr "नया वायरलेस नेटवर्क बनाएँ"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:122
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/desktop/meshbox.py:248 ../src/jarabe/desktop/meshbox.py:537
+msgid "Connecting..."
+msgstr "कनेक्ट हो रहा है..."
+
+#: ../extensions/deviceicon/network.py:126
+#: ../extensions/deviceicon/network.py:198
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:254 ../src/jarabe/desktop/meshbox.py:543
+msgid "Connected"
+msgstr "कनेक्टेड"
+
+#: ../extensions/deviceicon/network.py:158
+msgid "Channel"
+msgstr "माध्यम"
+
+#: ../extensions/deviceicon/network.py:173
+msgid "Wired Network"
+msgstr "वायर्ड नेटवर्क"
+
+#: ../extensions/deviceicon/network.py:201
+msgid "Speed"
+msgstr "गति"
+
+#: ../extensions/deviceicon/network.py:228
+msgid "Wireless modem"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:276
+msgid "Please wait..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:279
+#: ../src/jarabe/desktop/meshbox.py:164 ../src/jarabe/desktop/meshbox.py:494
+msgid "Connect"
+msgstr "कनेक्ट"
+
+#: ../extensions/deviceicon/network.py:280
+msgid "Disconnected"
+msgstr "सम्पर्क टूट गया"
+
+#: ../extensions/deviceicon/network.py:283
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "रद्द करें"
+
+#: ../extensions/deviceicon/network.py:287
+#: ../src/jarabe/desktop/meshbox.py:168
+msgid "Disconnect"
+msgstr "डिस्कनेक्ट"
+
+#: ../extensions/deviceicon/network.py:530
+#, python-format
+#, fuzzy
+msgid "%s's network"
+msgstr "%s का नेटवर्क %s"
+
+#: ../extensions/deviceicon/network.py:597
+#: ../extensions/deviceicon/network.py:656
+msgid "Mesh Network"
+msgstr "मेश नेटवर्क "
+
+#: ../extensions/deviceicon/network.py:857
+#, python-format
+msgid "Data sent %d kb / received %d kb"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:868
+msgid "Connection time "
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "मेरे स्पीकर"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "मौन हटाएँ"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "मौन"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "जाल"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "समूह"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "घर"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "क्रिया"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "पटचित्र"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "\"%s\" का स्क्रीनशॉट"
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Backup URL"
+msgstr "बैकअप यूआरएल"
+
+#: ../data/sugar.schemas.in.h:3
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"XO प्रतीक के लिए रंग जिसे पूरे डेस्कटॉप में प्रयोग में लिया जाएगा. स्ट्रिंग "
+"को स्ट्रोक रंग तथा भरने के रंग से बनाया गया है तथा आरजीबी रंग फ़ॉर्मेट में "
+"है. उदाहरण: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Corner Delay"
+msgstr "किनारा देरी"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Default font face"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font size"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default nick"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Delay for the activation of the frame using the corners."
+msgstr "कोना का प्रयोग करते हुए फ्रेम एक्टिवेशन में देरी"
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the edges."
+msgstr "किनारा का प्रयोग करते हुए फ्रेम एक्टिवेशन में देरी"
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Edge Delay"
+msgstr "किनारा देरी"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Favorites Layout"
+msgstr "पसंदीदा ख़ाका"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Favorites resume mode"
+msgstr "पसंदीदा रेज्यूम मोड"
+
+#: ../data/sugar.schemas.in.h:13
+#, fuzzy
+msgid "Font face that is used throughout the desktop."
+msgstr "प्रयोक्ता नाम जिसका प्रयोग पूरे डेस्कटॉप में किया जाना है."
+
+#: ../data/sugar.schemas.in.h:14
+#, fuzzy
+msgid "Font size that is used throughout the desktop."
+msgstr "प्रयोक्ता नाम जिसका प्रयोग पूरे डेस्कटॉप में किया जाना है."
+
+#: ../data/sugar.schemas.in.h:15
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"यदि सही है, सुगर हमें जैबर सर्वर के अन्य प्रयोक्ताओं के लिए खोजने लायक बना "
+"देगा."
+
+#: ../data/sugar.schemas.in.h:16
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "यदि सही है, सुगर \"लॉग आउट\" विकल्प दिखाएगा."
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Jabber Server"
+msgstr "जैबर सर्वर"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Keyboard layouts"
+msgstr "कुंजीपट ख़ाका"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Keyboard model"
+msgstr "कुंजीपट मॉडल"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Keyboard options"
+msgstr "कुंजीपट विकल्प"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Layout of the favorites view."
+msgstr "पसंदीदा दृश्य का ख़ाका."
+
+#: ../data/sugar.schemas.in.h:22
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+"कुंजीपट खाका की सूची. प्रत्येक सूची खाका फ़ॉर्म (वेरिएंट) में होनी चाहिए"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "List of keyboard options."
+msgstr "कुंजीपट विकल्पों की सूची."
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Power Automatic"
+msgstr "स्वचलित पावर"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Power Automatic."
+msgstr "स्वचलित पावर."
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Power Extreme"
+msgstr "एक्सट्रीम पावर"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Power Extreme."
+msgstr "एक्सट्रीम पावर."
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Publish to Gadget"
+msgstr "गॅजेट में प्रकाशित करें"
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Setting for muting the sound device."
+msgstr "आवाज उपकरण को मौन करने के लिए सेटिंग."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Show Log out"
+msgstr "लाग आउट दिखाएँ"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Sound Muted"
+msgstr "आवाज मौन है"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "The keyboard model to be used"
+msgstr "कुंजीपट मॉडल जिसे प्रयोग करना है"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Timezone setting for the system."
+msgstr "सिस्टम के लिए समयक्षेत्र सेटिंग."
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Url of the jabber server to use."
+msgstr "प्रयोग किए जाने वाले जैबर सर्वर का यूआरएल."
+
+#: ../data/sugar.schemas.in.h:36
+msgid "Url where the backup is saved to."
+msgstr "यूआरएल जहाँ बैकअप सहेजा जाना है."
+
+#: ../data/sugar.schemas.in.h:37
+msgid "User Color"
+msgstr "प्रयोक्ता रंग"
+
+#: ../data/sugar.schemas.in.h:38
+msgid "User Name"
+msgstr "प्रयोक्ता नाम"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "User name that is used throughout the desktop."
+msgstr "प्रयोक्ता नाम जिसका प्रयोग पूरे डेस्कटॉप में किया जाना है."
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Volume Level"
+msgstr "आवाज़ स्तर"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Volume level for the sound device."
+msgstr "ध्वनि उपकरण के लिए आवाज स्तर."
+
+#: ../data/sugar.schemas.in.h:42
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"जब यह रेज्यूम मोड पर होगा, पसंदीदा प्रतीक पर क्लिक करने पर उक्त कार्य की "
+"अंतिम प्रविष्टि बहाल हो जाएगी."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"सुगर-कंट्रोल-पैनल: चेतावनी, एक ही नाम के एक से अधिक विकल्प मिले: %s मॉड्यूल: "
+"%r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "शुगर -कंट्रोल-पेनल: कुंजी =%s विकल्प उपलब्ध नही है"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "शुगर -कंट्रोल-पेनल: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"उपयोग: sugar-control-panel [ विकल्प ] key [ आर्गुमेंट ... ] \n"
+" सुगर वातावरण के लिए नियंत्रण. \n"
+" विकल्प: \n"
+" -h यह मदद दिखाकर बाहर हो जाता है \n"
+" -l सभी उपलब्ध विकल्पों की सूची देता है \n"
+" -h key इस कुंजी के बारे में जानकारी देता है \n"
+" -g key कुंजी का वर्तमान मूल्य प्राप्त करें \n"
+" -s key कुंजी का वर्तमान मूल्य सेट करता है \n"
+" -c key कुंजी का वर्तमान मूल्य साफ करता है \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "अपने बदलावो को उपयोग मे लाने के लिए शुगर को पुनरारंभ करे .\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "चेतावनी"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "परिवर्तनों के लिए कम्प्यूटर फिर से प्रारंभ करना आवश्यक है"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "परिवर्तनों को रद्द करें"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "बाद में"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "अभी फिर से प्रारंभ करें"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "सम्पन्न"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "ठीक"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "संस्करण %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "मिटाने हेतु पुष्टि"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "मिटाने की पुष्टि: क्या आप %s को हमेशा के लिए मिटा देना चाहते हैं?"
+
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "रखें"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:105
+msgid "Erase"
+msgstr "मिटाएँ"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "पसंदीदा मिटाएँ"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "पसंदीदा बनाएँ"
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "फ्रीफ़ॉर्म"
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "रिंग"
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "सर्पिल"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "बक्सा"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "त्रिभुज"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "पंजीकरण असफल"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "पंजीकरण सफल"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "आप अब अपने स्कूल के सर्वर से पंजीकृत हो चुके हैं."
+
+#: ../src/jarabe/desktop/favoritesview.py:630
+msgid "Register"
+msgstr "पंजीकृत करे"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "सॉफ़्टवेयर अद्यतन"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"अपने नये सॉफ़्टवेयर के साथ संगतता सुनिश्चित करने के लिए अपनी क्रियाओं को "
+"अद्यतन करें"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "अभी जाँचें"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "सूची दृश्य"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "पसंदीदा दृश्य"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "कुंजी का प्रकार"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "विश्वसनियता का प्रकार"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "WPA & WPA2 व्यक्तिगत"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "बेतार सुरक्षा:"
+
+#: ../src/jarabe/desktop/meshbox.py:492
+#, python-format
+#, fuzzy
+msgid "Mesh Network %d"
+msgstr "मेश नेटवर्क "
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:629
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:65 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "पुनरारंभ"
+
+#: ../src/jarabe/desktop/meshbox.py:634
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "जोड़े"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "सर्वर से कनेक्ट करें नहीं हो सका."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "सर्वर ने निवेदन पूरा नहीं किया."
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "अस्वीकार"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%dबा."
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%dकि.बा."
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%dमे.बा."
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "%s इसमें का- %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "%r से हस्तांतरण"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "स्वीकृत"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr "खारिज"
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "%r को हस्तांतरित करें"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "हटाएँ"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "खोलें"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "के साथ खोलें"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s क्लिपिंग"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "आसपडोस"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "रंग बदलने के लिए दबाए"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "पीछे जाएँ"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "अगला"
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:59
+msgid "Untitled"
+msgstr "बिना शीर्षक"
+
+#: ../src/jarabe/journal/expandedentry.py:243
+msgid "No preview"
+msgstr "कोई पूर्वावलोकन नहीं"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Kind: %s"
+msgstr "काइंड: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+msgid "Unknown"
+msgstr "अज्ञात"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Date: %s"
+msgstr "तारीख़: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Size: %s"
+msgstr "आकार: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:286 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "बिना तारीख़"
+
+#: ../src/jarabe/journal/expandedentry.py:293
+msgid "Participants:"
+msgstr "प्रतिभागी:"
+
+#: ../src/jarabe/journal/expandedentry.py:316
+msgid "Description:"
+msgstr "वर्णनः"
+
+#: ../src/jarabe/journal/expandedentry.py:341
+msgid "Tags:"
+msgstr "चिप्पियाँ:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "चिठ्ठा"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "ढूंढें"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "कभी भी"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "आज"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "कल से"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "पिछला हफ्ता"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "पिछला महीना"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "पिछला साल"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "कोई भी"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "मेरे दोस्त"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "मेरी कक्षा"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "कुछ भी"
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:83
+msgid "Copy"
+msgstr "नक़ल"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:68
+msgid "Start"
+msgstr "प्रारंभ"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "आपकी दैनिकी खाली है"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "कोई भी मेल खाती हुई प्रविष्टि नहीं है"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "खोज साफ करें"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "आपकी दैनिकी पूरी भरी है"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"नई प्रविष्टियों के लिए जगह बनाने के लिए कृपया कुछ पुरानी दैनिकी प्रविष्टियों "
+"को मिटाएँ."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "दैनिकी दिखाएँ"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "एक वस्तु चुनें"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "बंद करें"
+
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Resume with"
+msgstr "के साथ बहाल करें"
+
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start with"
+msgstr "के साथ प्रारंभ करें"
+
+#: ../src/jarabe/journal/palettes.py:91
+msgid "Send to"
+msgstr "को भेजें"
+
+#: ../src/jarabe/journal/palettes.py:100
+msgid "View Details"
+msgstr "विवरणों को देखें"
+
+#: ../src/jarabe/journal/palettes.py:178
+msgid "No friends present"
+msgstr "कोई मित्र उपस्थित नहीं है"
+
+#: ../src/jarabe/journal/palettes.py:183
+msgid "No valid connection found"
+msgstr "कोई भी वैध कनेक्शन नहीं मिला"
+
+#: ../src/jarabe/journal/palettes.py:211
+msgid "No activity to resume entry"
+msgstr "प्रविष्टि बहाल करने के लिए कोई क्रिया नहीं"
+
+#: ../src/jarabe/journal/palettes.py:213
+msgid "No activity to start entry"
+msgstr "प्रविष्टि प्रारंभ करने के लिए कोई क्रिया नहीं"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "दोस्त को हटाएँ "
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "दोस्त बनाओ"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "बन्दकरें"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "लॉगआउट"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "मेरे सेटिंग"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr " % s निमंत्रित करें "
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "शुरू हो रहा है"
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr "स्रोत देखें"
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "रूकें"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr "नया प्रारंभ करें"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "सामग्री दिखाएँ"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d मे.बा. रिक्त"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "इंस्टैंस स्रोत"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "स्रोत"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "क्रिया बंडल स्रोत"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "स्रोत देखें: %r"
+
+#~ msgid "Title"
+#~ msgstr "शीर्षक"
+
+#~ msgid "Version"
+#~ msgstr "संस्करण"
+
+#~ msgid "Date"
+#~ msgstr "तारीख़"
+
+#~ msgid "Unmount"
+#~ msgstr "अनमाउन्ट"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "गोपनियता का प्रकार"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#, fuzzy
+#~ msgid "Disconnecting..."
+#~ msgstr " सम्पर्क तोडे"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "स्कूल मेश पोर्टल से संपर्क हो गया है"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "स्कूल मेश पोर्टल की खोज मे..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "एक्सो मेश पोर्टल से संपर्क हो गया है"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "एक्सो मेश पोर्टल की खोज मे..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "सिंपल मेश से संपर्क हो गया है"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "सिंपल मेश शुरू हो रहा है"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "मेश अग्यात है"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "काटपट की वस्तु: %s"
+
+#~ msgid "off"
+#~ msgstr "बंद"
+
+#~ msgid "on"
+#~ msgstr "चालू"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "अनुमति नही है . इस विधि को चलाने के लिए आपका रूट मे होना आवश्यक है "
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "समयक्षेत्र की जानकारी मे गलती"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "समयक्षेत्र की नक़ल करने मे गलती (%s से) : %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "समयक्षेत्र की अनुमति बदली जा रही है: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "एक्सो के बारे मे "
+
+#~ msgid "Add to journal"
+#~ msgstr "चिठ्ठे मे जोड़ें"
+
+#~ msgid "Reboot"
+#~ msgstr " पुनरारंभ करें"
+
+#~ msgid "My Battery life"
+#~ msgstr "मेरी बैटरी की आयू"
+
+#~ msgid "Battery charging"
+#~ msgstr "बैटरी चार्ज हो रही है"
+
+#~ msgid "Battery discharging"
+#~ msgstr "बैटरी समाप्त हो रही है"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "बैटरी पूरी चार्ज है "
diff --git a/shell/po/ht.po b/shell/po/ht.po
new file mode 100644
index 0000000..86a54e2
--- /dev/null
+++ b/shell/po/ht.po
@@ -0,0 +1,583 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: 2008-03-12 09:14-0400\n"
+"Last-Translator: Jude Augusma <jayme2901@yahoo.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "Non"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "Klike pou chanje koulè"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr "Retounen"
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "Fini"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "Prochen"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "Retire zanmi"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "Fè zanmi"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "Envite sou %s"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "Retire"
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "Louvri"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Objè ekritwa: %s."
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "Tip kle:"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "Tip otantifikasyon:"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "Tip kod sekrè"
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr "Ekran projektwa"
+
+#: ../src/view/home/HomeBox.py:147
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+#, fuzzy
+msgid "Disconnect"
+msgstr "Dekonekte"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:118
+#, fuzzy
+msgid "Disconnecting..."
+msgstr "Dekonekte..."
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:152
+#, fuzzy
+msgid "Connecting..."
+msgstr "Dekonekte..."
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr "Rezo "
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr "Dekonekte..."
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr "Repwann"
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr "Rankontre"
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:40
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr "Dekonekte"
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr "Chanèl"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "Vwazinaj"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "Gwoup"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "Lakay"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "Aktivite"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "Sugar-kontwòl-panèl: kle=%s pa yon opsyon disponib"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "Sugar-kontwòl-panèl: %s"
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"Sèvi: Sugar-Kontwòl-panèl [opsyon] kle [args ... ]\n"
+" Kontwòl pou anvironman sugar. \n"
+" opsyon: \n"
+" -h montre mesaj èd sa epi soti \n"
+" -l fè lis tout opsyon disponib yo \n"
+" -h kle montre enfòmasyon sou kle sa \n"
+" -g kle pwan valè kouran kle-a \n"
+" -s kle fikse valè Kouran pou kle-a \n"
+" "
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Pou aplike chanjman ou yo ou bezwen reyinisyalize program nan.\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr "Erè nan modifikatè endike koulè yo"
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr "Erè nan koulè endike yo"
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "Pa disponib"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr "Erè lè lokal pa egziste."
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+#, fuzzy
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Pa ka rantre %s. Kreye reglaj estanda"
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Lang pou kod=%s pa ka tèmine."
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Mwen regrèt mwen pa pale '%s'."
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr "Yo pa konnen eta l'"
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr "Erè nan itilizasyon limen/etenn agiman radio endike-a. "
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:134
+#, fuzzy
+msgid "Click to change your color:"
+msgstr "Klike pou chanje koulè"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr "Konekte sou rezo lekòl la"
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr "Ap chache rezo lekòl la"
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr "Konekte sou yon rezo XO"
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Ap chache yon rezo XO..."
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr "Konekte sou yon senp rezo"
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr "Kòmanse yon senp rezo"
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr "Rezo non idantifye"
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr "Fèmen"
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr "Enskri"
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr "ap louvri"
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr "Stope, rete"
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#~ msgid "off"
+#~ msgstr "Etenn"
+
+#~ msgid "on"
+#~ msgstr "Limen"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "Pèmisyon renye. Ou bezwen nan rasin nan pou metòd sa mache."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "Erè nan lèkti lè lokal"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Erè nan kopye lè lokal la (de %s): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Pèmisyon pou chanje lè lokal: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "Apwopo XO sa"
+
+#~ msgid "Add to journal"
+#~ msgstr "Ajoute jounal"
+
+#~ msgid "Reboot"
+#~ msgstr "Reyinisyalize"
+
+#~ msgid "My Battery life"
+#~ msgstr "Dire de tan batri m' nan"
+
+#~ msgid "Battery charging"
+#~ msgstr "Batri ap chaje"
+
+#~ msgid "Battery discharging"
+#~ msgstr "Batri ap dechaje"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Batri foul chaj"
diff --git a/shell/po/hu.po b/shell/po/hu.po
new file mode 100644
index 0000000..63d4e34
--- /dev/null
+++ b/shell/po/hu.po
@@ -0,0 +1,764 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-25 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/window.py:93 ../src/controlpanel/aboutme/view.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/window.py:125
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/window.py:175 ../src/journal/detailview.py:119
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/window.py:189 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/window.py:192
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:60
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:63
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:92
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:51
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:56 ../src/view/clipboardmenu.py:78
+msgid "Open"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:61 ../src/view/home/HomeBox.py:84
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:83
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:228
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:17
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:31
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:36
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/view/Shell.py:251
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:78
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:80
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:87 ../src/view/palettes.py:120
+#: ../src/journal/journaltoolbox.py:335 ../src/journal/palettes.py:75
+msgid "Erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:117
+msgid "Software Update"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:118
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:122 ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:124 ../src/controlpanel/gui.py:273
+msgid "Later"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:127
+msgid "Check now"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:261
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:262
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:320
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:321
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:159
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:166
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:218 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:221 ../src/view/devices/network/wireless.py:125
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/view/home/MeshBox.py:309 ../src/view/palettes.py:61
+#: ../src/journal/journaltoolbox.py:399 ../src/journal/palettes.py:57
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:314 ../src/view/frame/activitiestray.py:206
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:125
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:128
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:143
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/controlpanel/cmd.py:35
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:48
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:305
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:42 ../src/controlpanel/gui.py:265
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:264
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:268
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:277
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:76
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:87
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:90
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:32
+#: ../src/controlpanel/aboutme/__init__.py:22
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/model.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:55
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:64
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:87
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:96
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:111
+msgid "Sugar:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:126
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:148
+msgid "Copyright and License"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:156
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:163
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:175
+msgid "Full license:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/__init__.py:21
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/datetime/model.py:89
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/datetime/view.py:68
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/frame/model.py:38 ../src/controlpanel/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:114
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:131
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/language/view.py:70
+#: ../src/controlpanel/language/__init__.py:21
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:62
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:82
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:28
+#: ../src/controlpanel/network/__init__.py:21
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:54
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:62
+msgid "Turn of the wireless radio to save battery life"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:75
+msgid "Radio"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:91
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:100
+msgid "Discard network history"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:113
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:122
+msgid "Server:"
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:55
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:84
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:211
+msgid "Decline"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:107
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:189
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:401
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:442
+msgid "Triangle"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:295
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:296
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:298
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:299
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:420
+msgid "Settings"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:425
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:430
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:436
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/view/palettes.py:104 ../src/journal/journaltoolbox.py:402
+#: ../src/journal/palettes.py:59
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:138
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:142
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:191
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:215
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:62
+msgid "Search"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:119
+msgid "Anytime"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:121
+msgid "Today"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:123
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/journal/journaltoolbox.py:125
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/journal/journaltoolbox.py:127
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/journal/journaltoolbox.py:129
+msgid "Past year"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:136
+msgid "Anyone"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:138
+msgid "My friends"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:139
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/journal/journaltoolbox.py:255
+msgid "Anything"
+msgstr ""
+
+#. TODO: Add "Start with" menu item
+#: ../src/journal/journaltoolbox.py:325 ../src/journal/palettes.py:67
+msgid "Copy"
+msgstr ""
+
+#: ../src/journal/collapsedentry.py:248 ../src/journal/expandedentry.py:176
+#: ../src/journal/palettes.py:51
+msgid "Untitled"
+msgstr ""
+
+#: ../src/journal/journalactivity.py:119 ../src/journal/volumesmanager.py:57
+msgid "Journal"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:222
+msgid "No preview"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:241
+msgid "Participants:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:266
+msgid "Description:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:292
+msgid "Tags:"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:134
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:139
+msgid "Close"
+msgstr ""
+
+#: ../src/journal/volumestoolbar.py:93
+msgid "Unmount"
+msgstr ""
+
+#: ../src/journal/misc.py:95
+msgid "No date"
+msgstr ""
+
+#: ../src/journal/listview.py:39
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/journal/listview.py:40
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/journal/modalalert.py:59
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/journal/modalalert.py:63
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/journal/modalalert.py:75
+msgid "Show Journal"
+msgstr ""
diff --git a/shell/po/id.po b/shell/po/id.po
new file mode 100644
index 0000000..93c6b6e
--- /dev/null
+++ b/shell/po/id.po
@@ -0,0 +1,958 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-31 00:30-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:26
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:59
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:68
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:90
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:99
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:114
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:130
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:145
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:168
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:176
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:183
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:195
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:19
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:32
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:56
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:64
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:77
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:93
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:102
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:115
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:123
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:133
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:56
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:153
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:40
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:104
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:109
+#: ../src/jarabe/desktop/meshbox.py:246
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:113
+#: ../extensions/deviceicon/network.py:166
+#: ../src/jarabe/desktop/meshbox.py:252
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:126
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:141
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:169
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:46
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:128
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:131
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:50
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:196
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:205
+#: ../src/jarabe/frame/zoomtoolbar.py:42
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:212
+msgid "Document"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:226
+#: ../src/jarabe/journal/objectchooser.py:141
+msgid "Close"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:272
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:273
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:276
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281 ../src/jarabe/desktop/homebox.py:113
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:111
+#: ../src/jarabe/frame/activitiestray.py:683
+#: ../src/jarabe/frame/activitiestray.py:762
+#: ../src/jarabe/frame/activitiestray.py:790
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:334
+msgid "Ok"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:114
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:196
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:341
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:408
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:449
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:329
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:666
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:67
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:69
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73 ../src/jarabe/frame/clipboardmenu.py:62
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:76
+#: ../src/jarabe/journal/journaltoolbox.py:357
+#: ../src/jarabe/journal/palettes.py:112 ../src/jarabe/view/palettes.py:127
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:106
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:107
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:116
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:233
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:234
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:296
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:297
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:304
+msgid "Resume by default"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:130
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:134
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:440
+#: ../src/jarabe/frame/activitiestray.py:707
+#: ../src/jarabe/journal/journaltoolbox.py:425
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:62
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:445
+#: ../src/jarabe/frame/activitiestray.py:221
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:18
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:35
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:40
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:226
+#: ../src/jarabe/frame/activitiestray.py:655
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:608
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:610
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:612
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:629
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:640
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:673
+#: ../src/jarabe/frame/activitiestray.py:780
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:751
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:47
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:36
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:38
+msgid "Group"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:40
+msgid "Home"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/collapsedentry.py:258
+#: ../src/jarabe/journal/expandedentry.py:159
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:205
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:224
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:247
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:273
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:65
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:124
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:141
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:271
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:347
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:75 ../src/jarabe/view/palettes.py:111
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:40
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:41
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:369
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:136
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:61
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:64
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:81
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:86
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:91
+msgid "Restart"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:96
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:131
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:43
+msgid "Starting..."
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:73
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:145
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:149
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:201
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:223 ../src/jarabe/view/palettes.py:272
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:248
+msgid "Unmount"
+msgstr ""
diff --git a/shell/po/ig.po b/shell/po/ig.po
new file mode 100644
index 0000000..7287d5e
--- /dev/null
+++ b/shell/po/ig.po
@@ -0,0 +1,448 @@
+# translation of sugar.po to Igbo
+# translation of sugar.po to
+# This file is distributed under the same license as the PACKAGE package.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER, 2006.
+# Onye, Sylvester <sylvester@wazobialinux.com>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2006-07-07 10:23+0100\n"
+"Last-Translator: Onye, Sylvester <sylvester@wazobialinux.com>\n"
+"Language-Team: Igbo\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10.2\n"
+
+#: ../shell/PresenceWindow.py:62
+msgid "Who's around:"
+msgstr "Onye nọ ya:"
+
+#: ../shell/PresenceWindow.py:104
+msgid "Share"
+msgstr "Òkè"
+
+#: ../shell/StartPage.py:189
+msgid "Search"
+msgstr "Chọ̀ọ́"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Àzụ́"
+
+#: ../activities/browser/NavigationToolbar.py:23
+msgid "Forward"
+msgstr "Íhú"
+
+#: ../activities/browser/NavigationToolbar.py:29
+msgid "Reload"
+msgstr "Bubatagharịa"
+
+#: ../shell/shell.py:333
+msgid "Everyone"
+msgstr "Onyeọbụla"
+
+#: ../sugar/chat/ChatEditor.py:43
+msgid "Send"
+msgstr "Ziga"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/is.po b/shell/po/is.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/is.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/it.po b/shell/po/it.po
new file mode 100644
index 0000000..d9a8548
--- /dev/null
+++ b/shell/po/it.po
@@ -0,0 +1,1668 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-11 00:32-0500\n"
+"PO-Revision-Date: 2010-03-17 17:21+0200\n"
+"Last-Translator: Carlo Falciola <cfalciola@yahoo.it>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 2.0.3\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Informazioni su"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Devi inserire un nome."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "linea: colore=%s tinta=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "linea: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "riempimento: colore=%s tinta=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "riempimento: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Errore nella variazione dei colori richiesta"
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Errore nella definizione dei colori."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "Nome:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Seleziona per cambiare il tuo colore:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Il mio Computer"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Non disponibile"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Identità"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Numero di Serie:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Software"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Build:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "Wireless Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Copyright e Licenza"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Sugar è l'interfaccia utente che stai utilizzando in questo istante. Sugar è "
+"Software Libero, protetto dalla licenza General Public License di GNU, e "
+"chiunque è il benvenuto per apportare modifiche e migliorie e/o distribuirne "
+"copie, alle condizioni descritte nella licenza medesima."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Testo della Licenza:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Data e Ora"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Errore, timezone non esistente."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:33
+msgid "Timezone"
+msgstr "Timezone"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Cornice"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Valore deve essere un intero."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "mai"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "istantaneamente"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s secondi"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Ritardo attivazione"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Angolo"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Margine"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "Tastiera"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "Modello Tastiera"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "Tasto/i per cambiare la disposizione"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "Disposizione Tastiera"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Lingua"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Impossibile accedere a ~/.i18n. Creazione configurazione standard."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Linguaggio con codice=%s sconosciuto."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Spiacente, ma non parlo '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"Aggiungi i linguaggi nell'ordine che preferisci. Se una traduzione non fosse "
+"disponibile, verrà utilizzata quella successiva della lista."
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr "Configurazione del modem"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:90
+msgid "Username:"
+msgstr "Utente:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:101
+msgid "Password:"
+msgstr "Password:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:112
+msgid "Number:"
+msgstr "Numero:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:123
+msgid "APN:"
+msgstr "APN:"
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Network"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Stato sconosciuto."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Errore nel campo specificato, utilizzare on/off."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Errore nel campo specificato, utilizzare 0/1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Wireless"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Spegni il trasmettitore wireless per risparmiare carica della batteria"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Radio"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+"Elimina la storia delle connessioni di rete effettuate nel caso di problemi "
+"di connessione"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Elimina la storia delle connessioni di rete"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Collaborazione"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"Il Server equivale alla stanza in cui si sta; le persone collegate allo "
+"stesso server sono in grado di vedersi fra loro, anche se collegate a reti "
+"differenti."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Server:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Energia"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+"Errore nel campo Gestione Automatica Risparmio Energetico, utilizza on/off"
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Errore nel campo Gestione Estrema Risparmio Energetico, utilizza on/off"
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Gestione Risparmio Energetico (power management)"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+"Gestione Automatica Risparmio Energetico (incrementa la durata delle "
+"batterie)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Gestione Risparmio Energetico Estrema (spegne la connessione radio wireless, "
+"incrementa la durata delle batterie)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Aggiornamento software"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"Gli aggiornamenti software correggono errori, eliminano vulnerabilità del "
+"codice ed offrono nuove funzioni. "
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "Verifica %s..."
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "Scaricando %s..."
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "Aggirnamento %s..."
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "Il tuo software è aggiornato"
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "Puoi installare %s aggiornamento"
+msgstr[1] "Puoi installare %s aggiornamenti"
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "Ricerca aggiornamenti..."
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "Installazione aggiornamenti..."
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s aggiornamento è stato installato"
+msgstr[1] "%s aggiornamenti sono stati installati"
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "Installa selezionati"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "Dimensione dati da scaricare: %s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "Dalla versione %(current)d alla %(new)s (Dimensione: %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "Nessuno"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1 KB"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f KB"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "La mia Batteria"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Rimosso"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Caricando"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Pochissima carica rimanente"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d rimanenti"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Carica"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "Indirizzo IP: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:111
+msgid "Disconnect..."
+msgstr "Disconnessione..."
+
+#: ../extensions/deviceicon/network.py:116
+msgid "Create new wireless network"
+msgstr "Crea una nuova rete wireless"
+
+#: ../extensions/deviceicon/network.py:122
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/desktop/meshbox.py:248 ../src/jarabe/desktop/meshbox.py:537
+msgid "Connecting..."
+msgstr "Connessione..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:126
+#: ../extensions/deviceicon/network.py:198
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:254 ../src/jarabe/desktop/meshbox.py:543
+msgid "Connected"
+msgstr "Connesso"
+
+#: ../extensions/deviceicon/network.py:158
+msgid "Channel"
+msgstr "Canale"
+
+#: ../extensions/deviceicon/network.py:173
+msgid "Wired Network"
+msgstr "Rete su cavo"
+
+#: ../extensions/deviceicon/network.py:201
+msgid "Speed"
+msgstr "Velocità"
+
+#: ../extensions/deviceicon/network.py:228
+msgid "Wireless modem"
+msgstr "Modem Wireless"
+
+#: ../extensions/deviceicon/network.py:276
+msgid "Please wait..."
+msgstr "Attendi..."
+
+#: ../extensions/deviceicon/network.py:279
+#: ../src/jarabe/desktop/meshbox.py:164 ../src/jarabe/desktop/meshbox.py:494
+msgid "Connect"
+msgstr "Connetti"
+
+#: ../extensions/deviceicon/network.py:280
+msgid "Disconnected"
+msgstr "Disconnesso"
+
+#: ../extensions/deviceicon/network.py:283
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "Cancella"
+
+#: ../extensions/deviceicon/network.py:287
+#: ../src/jarabe/desktop/meshbox.py:168
+msgid "Disconnect"
+msgstr "Disconnetti"
+
+#: ../extensions/deviceicon/network.py:530
+#, python-format
+msgid "%s's network"
+msgstr "rete di %s"
+
+# A complete translation in italian: "rete a maglie" becames a tautology
+#: ../extensions/deviceicon/network.py:597
+#: ../extensions/deviceicon/network.py:656
+msgid "Mesh Network"
+msgstr "Rete Mesh"
+
+#: ../extensions/deviceicon/network.py:857
+#, python-format
+msgid "Data sent %d kb / received %d kb"
+msgstr "Dati %d kb inviati / %d kb ricevuti"
+
+#: ../extensions/deviceicon/network.py:868
+msgid "Connection time "
+msgstr "Tempo di connessione"
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "I miei Altoparlanti"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Attiva"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Silenzia"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "Mesh"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Gruppo"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Casa"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Attività"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "Schermata"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "Schermata di \"%s\""
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr ""
+"se \"disabled\" viene richiesto il nome alla inizializzazione; se \"system\" "
+"verrà utilizzato il nome presente nell'account UNIX."
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Backup URL"
+msgstr "URL di salvataggio"
+
+#: ../data/sugar.schemas.in.h:3
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"Colore per l'icona XO che viene utilizzata nel sistema. La stringa è "
+"composta dal colore della linea e dal colore del riempimento, il formato è "
+"quello dei colori rbg. Esempio: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Corner Delay"
+msgstr "Ritardo dell'angolo"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Default font face"
+msgstr "Tipo di carattere di default"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font size"
+msgstr "Dimensione del carattere di default"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default nick"
+msgstr "Nome di default"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+"Ritardo nella attivazione della cornice portando il puntatore in un angolo."
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Ritardo nella attivazione della cornice portando il puntatore sui bordi"
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Edge Delay"
+msgstr "Ritardo del bordo"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Favorites Layout"
+msgstr "Disposizione delle attività preferite"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Favorites resume mode"
+msgstr "Modalità di richiamo delle attività preferite"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Font face that is used throughout the desktop."
+msgstr "Tipo di carattere di default utilizzato in tutto il sistema."
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Font size that is used throughout the desktop."
+msgstr "Dimensione del carattere utilizzato in tutto il sistema."
+
+#: ../data/sugar.schemas.in.h:15
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"Se TRUE, Sugar renderà il computer rintracciabile dagli altri utenti del "
+"server Jabber."
+
+#: ../data/sugar.schemas.in.h:16
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "Se TRUE, Sugar mostrerà una opzione di \"Disconnessione\"."
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Jabber Server"
+msgstr "Jabber Server"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Keyboard layouts"
+msgstr "Disposizioni tastiera"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Keyboard model"
+msgstr "Modello tastiera"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Keyboard options"
+msgstr "Opzioni tastiera"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Layout of the favorites view."
+msgstr "Disposizione della vista dei favoriti."
+
+#: ../data/sugar.schemas.in.h:22
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+"Elenco di disposizioni della tastiera. Ogni voce deve essere nel formato "
+"layout(variant) "
+
+#: ../data/sugar.schemas.in.h:23
+msgid "List of keyboard options."
+msgstr "Lista di opzioni per la tastiera."
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Power Automatic"
+msgstr "Economizzazione Automatica"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Power Automatic."
+msgstr "Economizzazione Automatica."
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Power Extreme"
+msgstr "Economizzazione Massima"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Power Extreme."
+msgstr "Economizzazione Massima."
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Publish to Gadget"
+msgstr "Pubblica su Gadget"
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Setting for muting the sound device."
+msgstr "Selezione per silenziare il riproduttore sonoro."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Show Log out"
+msgstr "Mostra Disconnessione"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Sound Muted"
+msgstr "Suono Silenziato"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "The keyboard model to be used"
+msgstr "Modello di tastiera da utilizzare"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Timezone setting for the system."
+msgstr "Selezione per il Timezone del sistema"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Url of the jabber server to use."
+msgstr "Url del server jabber da utilizzare."
+
+#: ../data/sugar.schemas.in.h:36
+msgid "Url where the backup is saved to."
+msgstr "Url su cui effettuare i salvataggi."
+
+#: ../data/sugar.schemas.in.h:37
+msgid "User Color"
+msgstr "Colore dell'Utente "
+
+#: ../data/sugar.schemas.in.h:38
+msgid "User Name"
+msgstr "Nome Utente"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "User name that is used throughout the desktop."
+msgstr "Nome Utente utilizzato in tutto il sistema."
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Volume Level"
+msgstr "Livello Volume"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Volume level for the sound device."
+msgstr "Livello del volume del riproduttore di suoni."
+
+#: ../data/sugar.schemas.in.h:42
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"Quando è selezionata la modalità di ripresa, selezionando una delle icone "
+"delle attività favorite provocherà il riavvio della ultima versione "
+"utilizzata."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: ATTENZIONE, trovata più di una opzione avente lo stesso "
+"nome: %s modulo: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s non è una opzione disponibile"
+
+# non credo sia da tradurre....
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Utilizzo: sugar-control-panel [ opzioni ] key [ args ... ] \n"
+" Controllo dell'ambiente sugar. \n"
+" Opzioni: \n"
+" -h Mostra questo messaggio di aiuto ed esci\n"
+" -l lista tutte le opzioni disponibili \n"
+" -h key mostra informazioni sulla \"key\" \n"
+" -g key stampa il valore corrente della \"key\" \n"
+" -s key assegna il valore corrente alla \"key\" \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Per applicare le modifiche è necessario riavviare sugar.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "Attenzione"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Le modifiche rendono necessario un riavvio"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "Annulla modifiche"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Dopo"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "Riavvia adesso"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "Fatto"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "Versione %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "Conferma cancellazione"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+"Conferma cancellazione: Sei sicuro di voler eliminare definitivamente %s?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Memorizza"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:105
+msgid "Erase"
+msgstr "Elimina"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "Rimuovi preferito"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "Definisci preferito"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Formato libero"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Anello"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Spirale"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Scatola"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Triangolo"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "Registrazione Fallita"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "Registrazione Effettuata"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "Ora sei registrato sul tuo server di scuola"
+
+#: ../src/jarabe/desktop/favoritesview.py:630
+msgid "Register"
+msgstr "Registra"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Aggiornamento software"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"Aggiorna le tue attività perchè siano compatibili con il tuo sistema "
+"aggiornato."
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Verifica adesso"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Vista Elenco"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Visualizza i Preferiti"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "Tipo Chiave:"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "Tipo di Autenticazione:"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "WPA & WPA2 Personal"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "Wireless Security:"
+
+# A complete translation in italian: "rete a maglie" becames a tautology
+#: ../src/jarabe/desktop/meshbox.py:492
+#, python-format
+msgid "Mesh Network %d"
+msgstr "Rete Mesh %d"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:629
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:65 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "Riprendi"
+
+#: ../src/jarabe/desktop/meshbox.py:634
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "Associa"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "Impossibile connettersi al server."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "Il server non può completare la richiesta."
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "Rinuncia"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "%s di %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "Trasferisci da %r"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "Accetta"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr "Abbandona"
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "Trasferisci verso %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "Rimuovi"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "Apri"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "Apri con"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "ritaglio %s"
+
+# Letterale "Vicinato", sperimentale: I miei vicini
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "I miei vicini"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "Seleziona per cambiare colore:"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Indietro"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "Prossimo"
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:59
+msgid "Untitled"
+msgstr "Senza titolo"
+
+#: ../src/jarabe/journal/expandedentry.py:243
+msgid "No preview"
+msgstr "Nessuna anteprima"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Kind: %s"
+msgstr "Tipo: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+msgid "Unknown"
+msgstr "Sconosciuto"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Date: %s"
+msgstr "Data: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Size: %s"
+msgstr "Dimensione: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:286 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "Nessuna data"
+
+#: ../src/jarabe/journal/expandedentry.py:293
+msgid "Participants:"
+msgstr "Partecipanti:"
+
+#: ../src/jarabe/journal/expandedentry.py:316
+msgid "Description:"
+msgstr "Descrizione:"
+
+#: ../src/jarabe/journal/expandedentry.py:341
+msgid "Tags:"
+msgstr "Etichette:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Diario"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Cerca"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "Sempre"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Oggi"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Da ieri"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Settimana scorsa"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Mese scorso"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Anno scorso"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Tutti"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "I miei amici"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "La mia classe"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Qualsiasi"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:83
+msgid "Copy"
+msgstr "Copia"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:68
+msgid "Start"
+msgstr "Avvia"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "Il tuo Diario è vuoto"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "Non ci sono registrazioni corrispondenti"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "Annulla ricerca"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Il tuo Diario è pieno"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"Per favore cancella alcune registrazioni vecchie dal Diario per far spazio "
+"alle nuove."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Apri il Diario"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Scegli un oggetto"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Chiudi"
+
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Resume with"
+msgstr "Riprendi con"
+
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start with"
+msgstr "Inizia con"
+
+#: ../src/jarabe/journal/palettes.py:91
+msgid "Send to"
+msgstr "Invia a"
+
+#: ../src/jarabe/journal/palettes.py:100
+msgid "View Details"
+msgstr "Visualizza Dettagli"
+
+#: ../src/jarabe/journal/palettes.py:178
+msgid "No friends present"
+msgstr "Non ci sono amici presenti"
+
+#: ../src/jarabe/journal/palettes.py:183
+msgid "No valid connection found"
+msgstr "Connessione non trovata"
+
+#: ../src/jarabe/journal/palettes.py:211
+msgid "No activity to resume entry"
+msgstr "Sessione dell'Attività da riprendere non presente"
+
+#: ../src/jarabe/journal/palettes.py:213
+msgid "No activity to start entry"
+msgstr "Attività per riprendere la sessione non presente"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Rimuovi l'amico"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Aggiungi agli amici"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Spegni"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Disconnessione"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "Le mie Preferenze"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Invito per %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Inizio..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr "Visualizza Sorgente"
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "Chiudi"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr "Inizia nuovo"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "Mostra i contenuti"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB Liberi"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Sorgente Istanza"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Sorgente"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "Sorgente della Attività"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "Vedi codice sorgente: %r"
+
+#~ msgid "Title"
+#~ msgstr "Titolo"
+
+#~ msgid "Version"
+#~ msgstr "Versione"
+
+#~ msgid "Date"
+#~ msgstr "Data"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "Non riesco ad ottenere i dati necessari alla registrazione."
+
+#~ msgid "Unmount"
+#~ msgstr "Rimuovi"
+
+#~ msgid "Restart"
+#~ msgstr "Riavvia"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; e Contributori."
+
+#~ msgid "Document"
+#~ msgstr "Documento"
+
+#~ msgid "Resume by default"
+#~ msgstr "Riprendi per default"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Tipo di Crittografia:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid "Disconnecting..."
+#~ msgstr "Disconnessione..."
+
+#~ msgid "About my XO"
+#~ msgstr "Informazioni sul mio XO"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Connesso ad un Portale Mesh di scuola"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Ricerca di un Portale Mesh di scuola..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Connesso ad un Portale Mesh XO"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "Sto cercando un Portale Mesh XO..."
+
+# Diretto?
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Connesso ad un Mesh Semplice"
+
+# Diretto?
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Attivazione Mesh Semplice"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Mesh sconosciuto"
+
+#~ msgid "Settings"
+#~ msgstr "Configurazioni"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Oggetto Clipboard: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "Devi inserire un server."
+
+#~ msgid "Control Panel"
+#~ msgstr "Pannello di Controllo"
+
+#~ msgid "© 2008 One Laptop per Child Assocation "
+#~ msgstr "© 2008 One Laptop per Child Association "
+
+#~ msgid "Sugar is the graphical user interface that "
+#~ msgstr "Sugar è l'interfaccia grafica utente che "
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+# Ruota, piuttosto che anello per mantenere consistenza con lo shortcut da tastiera... cf 27_05_08
+#~ msgid "Ring view"
+#~ msgstr "Vista Ruota"
+
+#~ msgid "Remove from ring"
+#~ msgstr "Rimuovi dalla ruota"
+
+#~ msgid "Add to ring"
+#~ msgstr "Aggiungi alla ruota"
+
+#~ msgid "Changes require a sugar restart to take effect."
+#~ msgstr ""
+#~ "Le modifiche effettuate necessitano di un riavvio di Sugar per avere "
+#~ "effetto."
+
+#~ msgid "Changes require restart to take effect"
+#~ msgstr "Le modifiche effettuate necessitano di un riavvio per avere effetto"
+
+#~ msgid "Delay in milliseconds:"
+#~ msgstr "Ritardo in millisecondi:"
+
+#~ msgid "Hot Corners"
+#~ msgstr "Angoli sensibili"
+
+#, fuzzy
+#~ msgid "Warm Edges"
+#~ msgstr "Bordi Attivi"
+
+#~ msgid "off"
+#~ msgstr "spento"
+
+#~ msgid "on"
+#~ msgstr "acceso"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr ""
+#~ "Autorizzazione negata. E' necessario essere \"root\" per eseguire questo "
+#~ "metodo."
+
+#, fuzzy
+#~ msgid "Error in reading timezone"
+#~ msgstr "Errore nel timezone"
+
+#, python-format
+#, fuzzy
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Errore nella copia del timezone (da %s): %s"
+
+#, python-format
+#, fuzzy
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Modifica i permessi del timezone: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "Informazioni su questo XO"
+
+#~ msgid "Add to journal"
+#~ msgstr "Aggiungi al diario"
+
+#~ msgid "Reboot"
+#~ msgstr "Riavvia"
+
+#~ msgid "My Battery life"
+#~ msgstr "Durata Batteria"
+
+#~ msgid "Battery charging"
+#~ msgstr "Batteria in carica"
+
+#~ msgid "Battery discharging"
+#~ msgstr "Batteria in uso"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Batteria caricata completamente"
+
+#~ msgid "Text snippet"
+#~ msgstr "Parte di testo"
+
+#~ msgid "Image"
+#~ msgstr "Immagine"
+
+#~ msgid "Web Page"
+#~ msgstr "Pagina web"
+
+#~ msgid "PDF file"
+#~ msgstr "File PDF"
+
+#~ msgid "MS Word file"
+#~ msgstr "File MS Word"
+
+#~ msgid "RTF file"
+#~ msgstr "File RTF"
+
+#~ msgid "Abiword file"
+#~ msgstr "File Abiword"
+
+#~ msgid "Squeak project"
+#~ msgstr "Progetto Squeak"
+
+#~ msgid "OpenOffice text file"
+#~ msgstr "File di testo OpenOffice"
+
+#~ msgid "Object"
+#~ msgstr "Oggetto"
+
+#~ msgid "Pick a buddy picture"
+#~ msgstr "Scegli un'immagine"
+
+#~ msgid "My Picture:"
+#~ msgstr "La mia immagine:"
+
+#~ msgid "My Name:"
+#~ msgstr "Il mio nome:"
+
+#~ msgid "My Color:"
+#~ msgstr "Il mio color:"
+
+#~ msgid "Invite"
+#~ msgstr "Invita"
+
+#~ msgid "Stop download"
+#~ msgstr "Sospendi il trasferimento"
+
+#~ msgid "No options"
+#~ msgstr "Nessuna opzione"
+
+#~ msgid "Send"
+#~ msgstr "Invia"
+
+#~ msgid "Share with:"
+#~ msgstr "Condividi con:"
+
+#~ msgid "Private"
+#~ msgstr "Privato"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "Il mio Vicinato"
+
+#~ msgid "Undo"
+#~ msgstr "Annulla"
+
+#~ msgid "Redo"
+#~ msgstr "Ripeti"
+
+#~ msgid "Paste"
+#~ msgstr "Incolla"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "Attività %s"
+
+#, fuzzy
+#~ msgid "Keep error"
+#~ msgstr "Errore di scrittura"
+
+#, fuzzy
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "Errore di scrittura: tutte le modifiche verranno perse"
+
+#~ msgid "Don't stop"
+#~ msgstr "Non interrompere"
+
+#~ msgid "Stop anyway"
+#~ msgstr "Interrompi comunque"
+
+#~ msgid "Continue"
+#~ msgstr "Continua"
+
+#~ msgid "OK"
+#~ msgstr "OK"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d anno"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d anni"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d mese"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d mesi"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d settimana"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d settimane"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d giorno"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d giorni"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d ora"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d ore"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d minuto"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d minuti"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d secondo"
+
+#~ msgid " and "
+#~ msgstr " e "
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+# A complete translation in italian: "rete a maglie" becames a tautology
+# Diretto?
+# Ruota, piuttosto che anello per mantenere consistenza con lo shortcut da tastiera... cf 27_05_08
+#, python-format
+#~ msgid ", "
+#~ msgstr ", "
diff --git a/shell/po/ja.po b/shell/po/ja.po
new file mode 100644
index 0000000..bb96a0c
--- /dev/null
+++ b/shell/po/ja.po
@@ -0,0 +1,1558 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-11 00:32-0500\n"
+"PO-Revision-Date: 2010-03-23 06:29+0200\n"
+"Last-Translator: korakurider <korakurider@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\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"
+"X-Generator: Pootle 2.0.3\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "私について"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "名前の入力が必要です"
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "線: 色=%s 色相=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "線: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "塗りつぶし: 色=%s 色相=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "塗りつぶし: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "カラーモディファイアの指定でエラー"
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "色の指定でエラー"
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "名前:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "クリックして色を変更:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "私のコンピュータについて"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "不明です"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "個体の識別"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "シリアル番号:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "ソフトウェア"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "ビルド:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "ファームウェア:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "ワイヤレスファームウェア:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "著作権とライセンス"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Sugarは、あなたが見ているグラフィカルユーザインターフェースです。Sugarはフリーソフトウェアで、GNU General Public Licen"
+"se(一般公衆利用許諾契約書)による保護対象です。ここに記載されている条件の範囲で、Sugarを変更したりコピーを配布することが自由に行えます。"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "ライセンス全文:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "日付・時刻"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "エラー:そのタイムゾーンは存在しません。"
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:33
+msgid "Timezone"
+msgstr "タイムゾーン"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "フレーム"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "値は整数でなくてはなりません"
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "表示しない"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "すぐに表示"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s 秒"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "表示するまでの時間"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "画面の4すみ"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "画面のふち"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "キーボード"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "キーボードのモデル"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "レイアウト変更に使うキー"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "キーボードの配列"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "言語"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "~/.i18nにアクセスできませんでした。標準設定を作ってください。"
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "コード%sの言語が不明です。"
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "ごめんなさい。'%s'は話せません。"
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr "使いたい言語を順番に追加してください。翻訳されていないと、リストの次のものが使われます。"
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr "モデムの設定"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:90
+msgid "Username:"
+msgstr "ユーザ名:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:101
+msgid "Password:"
+msgstr "パスワード:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:112
+msgid "Number:"
+msgstr "番号:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:123
+msgid "APN:"
+msgstr "APN:"
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "ネットワーク"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "状態が不明です"
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "radio引数指定でエラー、on/offを使ってください。"
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "引数指定でエラー、0/1を使ってください。"
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "無線"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "電池を節約するため、無線を止める"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "電波"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "ネットワーク接続で問題がある場合、接続履歴を破棄します"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "ネットワーク接続履歴を破棄"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "コラボレーション"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr "サーバーは、あなたがいる部屋と同じようなものです。同じサーバー上にいる人は、違うネットワークにいてもお互いに相手が見えます。"
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "サーバー:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "電源"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "automatic_pm 引数指定でエラー、 on/offを指定してください"
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "extreme_pm 引数指定のエラー、 on/offを指定してください。"
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "電源の管理"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "自動的な電源管理(電池が長持ちします)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr "最大の電源管理(無線の電波を停めて、電池を長持ちさせます)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "ソフトウェアの更新"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr "ソフトウェアの更新により、エラーを修正し、セキュリティ脆弱性を減らし、新機能を追加します。"
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "%s を調べています..."
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "% をダウンロードしています..."
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "%s を更新しています..."
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "ソフトウェアは最新になっています"
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "%s の更新をインストールできます"
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "更新をチェックしています..."
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "更新をインストールしています..."
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s の更新がインストールされました"
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "選ばれているものをインストールする"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "ダウンロードのサイズ: %s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "現在のバージョン %(current)d から %(new)s (サイズ: %(size)s) へ"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "なし"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1KB"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f KB"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "私の電池"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "取り外されています"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "充電中"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "電池が残りわずかです"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "残り %(hour)d:%(min).2d"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "充電済み"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "IPアドレス: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:111
+msgid "Disconnect..."
+msgstr "切断..."
+
+#: ../extensions/deviceicon/network.py:116
+msgid "Create new wireless network"
+msgstr "無線ネットワークを作成"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:122
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/desktop/meshbox.py:248 ../src/jarabe/desktop/meshbox.py:537
+msgid "Connecting..."
+msgstr "接続しています..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:126
+#: ../extensions/deviceicon/network.py:198
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:254 ../src/jarabe/desktop/meshbox.py:543
+msgid "Connected"
+msgstr "接続しました"
+
+#: ../extensions/deviceicon/network.py:158
+msgid "Channel"
+msgstr "チャンネル"
+
+#: ../extensions/deviceicon/network.py:173
+msgid "Wired Network"
+msgstr "有線ネットワーク"
+
+#: ../extensions/deviceicon/network.py:201
+msgid "Speed"
+msgstr "速度"
+
+#: ../extensions/deviceicon/network.py:228
+msgid "Wireless modem"
+msgstr "無線モデム"
+
+#: ../extensions/deviceicon/network.py:276
+msgid "Please wait..."
+msgstr "お待ちください..."
+
+#: ../extensions/deviceicon/network.py:279
+#: ../src/jarabe/desktop/meshbox.py:164 ../src/jarabe/desktop/meshbox.py:494
+msgid "Connect"
+msgstr "接続"
+
+#: ../extensions/deviceicon/network.py:280
+msgid "Disconnected"
+msgstr "切断されました"
+
+#: ../extensions/deviceicon/network.py:283
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "中止"
+
+#: ../extensions/deviceicon/network.py:287
+#: ../src/jarabe/desktop/meshbox.py:168
+msgid "Disconnect"
+msgstr "切断"
+
+#: ../extensions/deviceicon/network.py:530
+#, python-format
+msgid "%s's network"
+msgstr "%s のネットワーク"
+
+#: ../extensions/deviceicon/network.py:597
+#: ../extensions/deviceicon/network.py:656
+msgid "Mesh Network"
+msgstr "メッシュネットワーク"
+
+#: ../extensions/deviceicon/network.py:857
+#, python-format
+msgid "Data sent %d kb / received %d kb"
+msgstr "送信 %d kb/受信 %d kb"
+
+#: ../extensions/deviceicon/network.py:868
+msgid "Connection time "
+msgstr "接続時間 "
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "私のスピーカー"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "音を出す"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "音を消す"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "メッシュ"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "グループ"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "ホーム"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "アクティビティ"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "スクリーンショット"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "\"%s\"のスクリーンショット"
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr "初期化の際ニックネームを確認する場合は \"disabled\"を、UNIXアカウントの長い名前を再利用するには\"system\"を指定してください"
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Backup URL"
+msgstr "バックアップURL"
+
+#: ../data/sugar.schemas.in.h:3
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"デスクトップで使われるXOアイコンの色。文字列は線と塗りつぶしの色で構成されます。フォーマットは赤青緑の形式です。例: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Corner Delay"
+msgstr "四隅の遅延"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Default font face"
+msgstr "デフォルトのフォント種類"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font size"
+msgstr "デフォルトのフォントサイズ"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default nick"
+msgstr "デフォルトのニックネーム"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Delay for the activation of the frame using the corners."
+msgstr "画面四隅でフレームを起動する際の遅延"
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the edges."
+msgstr "画面四辺でフレームを起動する際の遅延"
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Edge Delay"
+msgstr "四辺の遅延"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Favorites Layout"
+msgstr "お気に入りのレイアウト"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Favorites resume mode"
+msgstr "お気に入り復元モード"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Font face that is used throughout the desktop."
+msgstr "デスクトップで使われるフォント種類"
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Font size that is used throughout the desktop."
+msgstr "デスクトップで使われるフォントサイズ"
+
+#: ../data/sugar.schemas.in.h:15
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr "ONの場合、SugarはJabberサーバーの他のユーザが私たちを検索できるようにします"
+
+#: ../data/sugar.schemas.in.h:16
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "もしONなら、Sugarはログアウト オプションを表示します。"
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Jabber Server"
+msgstr "Jabberサーバー"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Keyboard layouts"
+msgstr "キーボードの配列"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Keyboard model"
+msgstr "キーボードのモデル"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Keyboard options"
+msgstr "キーボードのオプション"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Layout of the favorites view."
+msgstr "お気に入り表示のレイアウト"
+
+#: ../data/sugar.schemas.in.h:22
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr "キーボード配列のリスト。"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "List of keyboard options."
+msgstr "キーボードオプションのリスト"
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Power Automatic"
+msgstr "電源設定-自動"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Power Automatic."
+msgstr "電源設定-自動"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Power Extreme"
+msgstr "電源設定-最大"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Power Extreme."
+msgstr "電源設定-最大"
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Publish to Gadget"
+msgstr "ガジェットに送信"
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Setting for muting the sound device."
+msgstr "サウンド装置の音を消す"
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Show Log out"
+msgstr "ログアウト を表示"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Sound Muted"
+msgstr "消音されました"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "The keyboard model to be used"
+msgstr "使用するキーボードのモデル"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Timezone setting for the system."
+msgstr "システムのタイムゾーン設定"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Url of the jabber server to use."
+msgstr "使用するJabberサーバーのURL"
+
+#: ../data/sugar.schemas.in.h:36
+msgid "Url where the backup is saved to."
+msgstr "バックアップが保存されるURL"
+
+#: ../data/sugar.schemas.in.h:37
+msgid "User Color"
+msgstr "ユーザの色"
+
+#: ../data/sugar.schemas.in.h:38
+msgid "User Name"
+msgstr "ユーザの名前"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "User name that is used throughout the desktop."
+msgstr "デスクトップで使われるユーザ名"
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Volume Level"
+msgstr "音量レベル"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Volume level for the sound device."
+msgstr "サウンド装置の音量レベル"
+
+#: ../data/sugar.schemas.in.h:42
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr "復元モードの時、お気に入りアイコンをクリックすると、そのアクティビティで使用した最後のエントリが再開します"
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr "sugar-control-panel: 注意, 同じ名前のオプションが複数あります: %s モジュール: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s は有効なオプションではありません"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"使い方: sugar-control-panel [ option ] key [ args ... ] \n"
+"Sugarの環境を設定する。 \n"
+"Options: \n"
+"-h このヘルプメッセージを表示して終了する\n"
+"-l 全ての有効なオプションを表示\n"
+"-h key このキーについての情報を表示\n"
+"-g key このキーの現在の設定値を取得\n"
+"-s key このキーの値を設定 \n"
+"-c key このキーの設定を消去\n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "変更を適用するにはsugarを再起動しなければいけません。\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "注意"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "変更には再起動が必要です"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "変更を取りやめる"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "あとで"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "今すぐ再起動"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "完了"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "了解"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "バージョン %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "消去の確認"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "消去の確認: %s を完全に消去しますか?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "ジャーナルに保存"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:105
+msgid "Erase"
+msgstr "消去する"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "お気に入りから削除"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "お気に入りに登録"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "自由に並べる"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "円に並べる"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "渦巻きに並べる"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "箱型に並べる"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "三角形に並べる"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "登録失敗"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "登録成功"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "あなたはスクールサーバーに登録されました"
+
+#: ../src/jarabe/desktop/favoritesview.py:630
+msgid "Register"
+msgstr "登録"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "ソフトウェアの更新"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "新しいソフトウェアとの互換性を保つため、アクティビティを更新してください"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "今すぐ調べる"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "リスト表示"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "お気に入り"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "キーのタイプ:"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "認証タイプ:"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "WPA と WPA2パーソナル"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "無線のセキュリティ:"
+
+#: ../src/jarabe/desktop/meshbox.py:492
+#, python-format
+msgid "Mesh Network %d"
+msgstr "メッシュネットワーク %d"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:629
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:65 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "再開"
+
+#: ../src/jarabe/desktop/meshbox.py:634
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "参加"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "サーバーに接続できません"
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "サーバーは要求の処理を完了できませんでした"
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "断る"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "%s の %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "%rから転送"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "受け入れる"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr "閉じる"
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "%rへ転送"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "削除"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "開く"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "次のもので開く:"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%sのクリッピング"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "お隣さん"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "クリックして色を変更:"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "戻る"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "進む"
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:59
+msgid "Untitled"
+msgstr "タイトル無し"
+
+#: ../src/jarabe/journal/expandedentry.py:243
+msgid "No preview"
+msgstr "プレビュー無し"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Kind: %s"
+msgstr "種類: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+msgid "Unknown"
+msgstr "不明"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Date: %s"
+msgstr "日付: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Size: %s"
+msgstr "サイズ: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:286 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "日付無し"
+
+#: ../src/jarabe/journal/expandedentry.py:293
+msgid "Participants:"
+msgstr "参加者:"
+
+#: ../src/jarabe/journal/expandedentry.py:316
+msgid "Description:"
+msgstr "説明:"
+
+#: ../src/jarabe/journal/expandedentry.py:341
+msgid "Tags:"
+msgstr "タグ:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "ジャーナル"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "検索"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "すべての期間"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "今日"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "昨日から後"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "過去1週間"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "過去1ヶ月"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "過去1年"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "誰でも"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "私の友だち"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "私のクラス"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "すべての種類"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:83
+msgid "Copy"
+msgstr "コピー"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:68
+msgid "Start"
+msgstr "開始"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "ジャーナルが空です"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "あてはまるものが無いです"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "検索をクリア"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "ジャーナルが満杯です"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr "新しいものが入るよう、ジャーナルの中身の古いものをどれか削除してください"
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "ジャーナルを表示"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "オブジェクトを選ぶ"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "閉じる"
+
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Resume with"
+msgstr "次のアクティビティで再開"
+
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start with"
+msgstr "次のアクティビティで開始"
+
+#: ../src/jarabe/journal/palettes.py:91
+msgid "Send to"
+msgstr "次に送る"
+
+#: ../src/jarabe/journal/palettes.py:100
+msgid "View Details"
+msgstr "詳細を表示"
+
+#: ../src/jarabe/journal/palettes.py:178
+msgid "No friends present"
+msgstr "お友達がいません"
+
+#: ../src/jarabe/journal/palettes.py:183
+msgid "No valid connection found"
+msgstr "正しい接続がありません"
+
+#: ../src/jarabe/journal/palettes.py:211
+msgid "No activity to resume entry"
+msgstr "エントリを再開するアクティビティがありません"
+
+#: ../src/jarabe/journal/palettes.py:213
+msgid "No activity to start entry"
+msgstr "エントリを開始するアクティビティがありません"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "お友だちの登録削除"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "お友だちを登録"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "シャットダウン"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "ログアウト"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "私の設定"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "%s に招待する"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "起動中..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr "ソースコードを表示"
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "停止"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr "新しく開始する"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "内容を表示"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB 空き"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "インスタンスのソースコード"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "ソースコード"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "アクティビティバンドルのソースコード"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "ソースを表示: %r"
+
+#~ msgid "Title"
+#~ msgstr "表題"
+
+#~ msgid "Version"
+#~ msgstr "バージョン"
+
+#~ msgid "Date"
+#~ msgstr "日付"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "登録に必要なデータを取得できません"
+
+#~ msgid "Unmount"
+#~ msgstr "取りはずす"
+
+#~ msgid "Restart"
+#~ msgstr "再起動"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "(C) 2008 One Laptop per Child Association Inc; Red Hat Inc; and "
+#~ "Contributors."
+
+#~ msgid "Document"
+#~ msgstr "ドキュメント"
+
+#~ msgid "Resume by default"
+#~ msgstr "デフォルトのアクティビティで再開"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "暗号タイプ:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid "Disconnecting..."
+#~ msgstr "切断しています..."
+
+#~ msgid "About my XO"
+#~ msgstr "私のXOについて"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "スクールメッシュポータルに接続しました。"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "スクールメッシュポータルを探しています..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "XOメッシュポータルに接続しました"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "XOメッシュポータルを探しています..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "シンプルメッシュに接続しました"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "シンプルメッシュを開始しています"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "不明なメッシュ"
+
+#~ msgid "Settings"
+#~ msgstr "設定"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "クリップボードのオブジェクト: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "サーバーの指定が必要です"
+
+#~ msgid "Control Panel"
+#~ msgstr "コントロールパネル"
+
+#, fuzzy
+#~ msgid "off"
+#~ msgstr "オフ"
+
+#, fuzzy
+#~ msgid "on"
+#~ msgstr "オン"
+
+#, fuzzy
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "実行が拒否されました。このメソッドを実行するにはrootでなければいけません。"
+
+#, fuzzy
+#~ msgid "Error in reading timezone"
+#~ msgstr "タイムゾーンの読み取りでエラー"
+
+#, python-format
+#, fuzzy
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "(%sから)タイムゾーンをコピー中にエラー:%s"
+
+#, python-format
+#, fuzzy
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "タイムゾーンの権限変更でエラー:%s"
+
+#~ msgid "Add to journal"
+#~ msgstr "ジャーナルに追加"
+
+#~ msgid "Reboot"
+#~ msgstr "再起動"
+
+#, fuzzy
+#~ msgid "My Battery life"
+#~ msgstr "バッテリーの残り"
+
+#~ msgid "Battery charging"
+#~ msgstr "充電中"
+
+#, fuzzy
+#~ msgid "Battery discharging"
+#~ msgstr "放電中"
+
+#, fuzzy
+#~ msgid "Battery fully charged"
+#~ msgstr "充電完了"
+
+#, fuzzy
+#~ msgid "Share with:"
+#~ msgstr "共有するおともだち:"
+
+#, fuzzy
+#~ msgid "Private"
+#~ msgstr "プライベート"
+
+#, fuzzy
+#~ msgid "My Neighborhood"
+#~ msgstr "自分の周り"
+
+#, fuzzy
+#~ msgid "Undo"
+#~ msgstr "元に戻す"
+
+#, fuzzy
+#~ msgid "Redo"
+#~ msgstr "やり直す"
+
+#, fuzzy
+#~ msgid "Paste"
+#~ msgstr "ペースト"
+
+#, python-format
+#, fuzzy
+#~ msgid "%s Activity"
+#~ msgstr "%sアクティビティ"
+
+#, fuzzy
+#~ msgid "Keep error"
+#~ msgstr "エラーを記録"
+
+#, fuzzy
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "記録エラー発生:全ての変更は失われます"
+
+#, fuzzy
+#~ msgid "Don't stop"
+#~ msgstr "停止しない"
+
+#, fuzzy
+#~ msgid "Stop anyway"
+#~ msgstr "強制停止"
+
+#, fuzzy
+#~ msgid "Continue"
+#~ msgstr "続ける"
+
+#, fuzzy
+#~ msgid "OK"
+#~ msgstr "了解"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d year"
+#~ msgstr "%d年"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d years"
+#~ msgstr "%d年"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d month"
+#~ msgstr "%d月"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d months"
+#~ msgstr "%d月"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d week"
+#~ msgstr "%d週"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d weeks"
+#~ msgstr "%d週"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d day"
+#~ msgstr "%d日"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d days"
+#~ msgstr "%d日"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d hour"
+#~ msgstr "%d時間"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d hours"
+#~ msgstr "%d時間"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d minute"
+#~ msgstr "%d分"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d minutes"
+#~ msgstr "%d分"
+
+#, python-format
+#, fuzzy
+#~ msgid "%d second"
+#~ msgstr "%d秒"
+
+#~ msgid " and "
+#~ msgstr "と"
+
+#, fuzzy
+#~ msgid ", "
+#~ msgstr "、"
diff --git a/shell/po/km.po b/shell/po/km.po
new file mode 100644
index 0000000..110c316
--- /dev/null
+++ b/shell/po/km.po
@@ -0,0 +1,584 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Rit Lim <rit.lim@gmail.com>, 2008.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "ឈ្មោះ: "
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "ដូរ​ព័ណ"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr "ថយ​ក្រោយ"
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "រួច​ហើយ"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "ថតទៅ​មុខ"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "ដក​មិត្ត​ចេញ"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "កសាង​មិត្ត​ភាព"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "អញ្ជើញទៅ %s"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "យក​ចេញ"
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "បើក"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "ក្ដារ​ខ្ទាស់​វត្ថុ: %s."
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "ប្រភេទ​ឆ្នុច: "
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "ប្រភេទផ្ទៀង: "
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "ប្រភេទ​អ៊ិនគ្រីប: "
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr "រូបថត​អេក្រង់​"
+
+#: ../src/view/home/HomeBox.py:147
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+#, fuzzy
+msgid "Disconnect"
+msgstr "ផ្ដាច់"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:118
+#, fuzzy
+msgid "Disconnecting..."
+msgstr "ផ្ដាច់បណ្ដាញ"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:152
+#, fuzzy
+msgid "Connecting..."
+msgstr "ផ្ដាច់បណ្ដាញ"
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr "បណ្ដាញត"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr "ផ្ដាច់បណ្ដាញ"
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr "បន្ត"
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr "ចូល​រួម"
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:40
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr "ផ្ដាច់"
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr "ប៉ុស្ដិ៍"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "ភូមិ"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "ក្រុម"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "ផ្ទះ"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "សកម្មភាព"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s ជម្រើស​អត់​មាន​ទេ"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+"Control for the sugar environment. \n"
+"Options: \n"
+"-h show this help message and exit \n"
+"-l list all the available options \n"
+"-h key show information about this key \n"
+"-g key get the current value of the key \n"
+"-s key set the current value for the key \n"
+" "
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr "កំណែ​សំរាប់​ពណ៌​នេះ​មាន​បញ្ហា"
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr "ពណ៌​នេះ​មាន​បញ្ហា"
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "មិន​អាច​រក​បាន"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr "មានបញ្ហា ។ ដំបន់​ម៉ោង​នេះ​អត់​មាន​ទេ"
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+#, fuzzy
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "មិន​អាច​អាន %s បាន​ទេ ។ បង្កើតស្ដង់ដារ​​សំរាប់​ការ​រៀបចំ"
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "កូដ​សំរាប់​ភាលា​ code=%s មិន​អាន​រក​ឃើញ​ទេ"
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "សូម​ទោស ខ្ញុំ​មិន​ចេះ​និយាយ​ភាសា '%s' ទេ"
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr "ស្ថានភាព​មិន​ស្គាល់"
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr "​មាន​បញ្ហានៅ​ក្នុង​វិទ្យុនេះ"
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:134
+#, fuzzy
+msgid "Click to change your color:"
+msgstr "ដូរ​ព័ណ"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr "ផ្ជាប់នឹង​បណ្តាញ​ត​របស់​សាលា"
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr "ស្វែង​រក​បណ្តាញ​ត​របស់​សាលា"
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr "ផ្ជាប់​នឹង​បណ្ដាញត​ XO"
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr "ស្វែង​រក​បណ្តាញ​ត​របស់​ XO"
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr "ផ្ជាប់​នឹង​បណ្ដាញ​ស៊ីមផល"
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr "ចាប់​ផ្ដើម​បណ្ដាញ​ស៊ីមផល"
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr "បណ្ដាញ​គ្មាន​សំគាល់"
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr "បិទ"
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr "ចុះ​ឈ្មោះ"
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr "ចាប់​ផ្ដើម..."
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr "ឈប់"
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#~ msgid "off"
+#~ msgstr "បិត"
+
+#~ msgid "on"
+#~ msgstr "បើក"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "គ្មានអនុញ្ញាត ។ វិធី​សាស្ត្រ​នេះ​ត្រូវ​ការ​មេ​"
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "មាន​បញ្ហាក្នុង​ការ​អាន​ដំបន់ម៉ោង​"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "មាន​បញ្ហាក្នុង​ការ​ចំលង់​ដំបន់ម៉ោង​ (​ពី %s): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "​ដូរ​សេចក្ដី​អនុញ្ញាត​នៃ​ដំបន់​ម៉ោង: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "អំពី XO នេះ"
+
+#~ msgid "Add to journal"
+#~ msgstr "បញ្ចូលក្នុងកំណន់​ប្រចាំ​ថ្ងៃ"
+
+#~ msgid "Reboot"
+#~ msgstr "ចាប់​ផ្ដើម​ឡើង​វិញ"
+
+#~ msgid "My Battery life"
+#~ msgstr "អាយុថាមពល"
+
+#~ msgid "Battery charging"
+#~ msgstr "កំពុង​សាក​ថាមពល"
+
+#~ msgid "Battery discharging"
+#~ msgstr "កំពុង​ប្រើ​ថាមពល"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "ថាមពល​សាក​ពេញ​ហើយ"
diff --git a/shell/po/ko.po b/shell/po/ko.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/ko.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/kos.po b/shell/po/kos.po
new file mode 100644
index 0000000..2dac090
--- /dev/null
+++ b/shell/po/kos.po
@@ -0,0 +1,1211 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-26 00:31-0400\n"
+"PO-Revision-Date: 2009-09-02 21:21-0400\n"
+"Last-Translator: Chris Leonard <cjl@laptop.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: kos\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"
+"X-Generator: Pootle 1.2.1\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+msgid "None"
+msgstr ""
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:261
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:267
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:406
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:427
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:431
+msgid "Make favorite"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:401
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:442
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:463
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:468
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:34
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:51
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:56
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr ""
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr "Tui"
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:218
+msgid "Unmount"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr ""
diff --git a/shell/po/mg.po b/shell/po/mg.po
new file mode 100644
index 0000000..694551c
--- /dev/null
+++ b/shell/po/mg.po
@@ -0,0 +1,1213 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-26 00:31-0400\n"
+"PO-Revision-Date: 2009-05-21 15:10-0400\n"
+"Last-Translator: dina garnier oeliarisoa <dina.garnier.oeliarisoa@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: mg\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Pootle 1.2.1\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Momba ahy"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Tsy maintsy mampiditra anarana ianao"
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "Anarana:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Tsindrio raha hanova ny lokonao:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Ny momba ny solosaina"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Aoreno:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Faritra"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "eo no ho eo"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Fiteny"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Tsy fantatra ny fitenin'ny sora-drindra=%s."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Azafady izaho tsy miteny '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Tsy misy taroby"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Fiaraha-miasa"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Mpamatsy, Mpizara"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Hery, Tanjaka"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+#, fuzzy
+msgid "None"
+msgstr "Vita"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Esory"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr "Adiresy IP: %s"
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:261
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:267
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Avereno ny feo"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Esory ny feo"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr "Tahirizo ny URL"
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr "Nesorina ny feo"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr "Url misy ny tahiry."
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr "Lokon'ny mpampiasa"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr "Anaran'ny mpampiasa"
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr "Fanovàna ny hadirim-peo."
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr "Tandremo"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr "Foano ny fanovàna"
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Amin'ny manaraka"
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "Vita"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr "Foano"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:406
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr "Soloy"
+
+#: ../src/jarabe/desktop/activitieslist.py:427
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:431
+msgid "Make favorite"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:401
+msgid "Box"
+msgstr "Boaty"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:442
+msgid "Triangle"
+msgstr "Telozoro"
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr "Nisy olana ny fisoratana anarana"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr "Vita soa aman-tsara ny fisoratana anarana"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr "Voasoratra anarana"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:463
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:468
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:34
+msgid "Cannot obtain data needed for registration."
+msgstr "Tsy azo ny laza ilaina amin'ny fisoratana anarana."
+
+# je proposerai aussi "Tsy afaka mifandray amin'ny mpamatsy". Cela dépend si on souhaite traduire "server" par "mpizara" ou "mpamatsy".
+#: ../src/jarabe/desktop/schoolserver.py:51
+msgid "Cannot connect to the server."
+msgstr "Tsy afaka mifandray amin'ny mpizara."
+
+#: ../src/jarabe/desktop/schoolserver.py:56
+msgid "The server could not complete the request."
+msgstr "Tsy afaka mameno ny fangatahana ny mpamatsy."
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr "Ekeo"
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr "Fafao"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "Sokafy"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "Sokafy miaraka amin'ny"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Ny manodidina"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "Tsindrio raha te hanova ny loko:"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Miverina"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "Manaraka"
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "Tsy misy lohateny"
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr "Mombamomba:"
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Firaiketana"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Tadiavo"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Anio, Androany"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Nanomboka omaly"
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Tamin'ny herinandro lasa"
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Tamin'ny iray volana"
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Tamin'ny herin-taona"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Ny olona rehetra"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Ny namako"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Ny kilasiko"
+
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "Adikao"
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr "Atomboy"
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr "Tsy misy n'inoninona ao anatin'ny firaiketanao"
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Feno ny firaiketanao"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Asehoy ny firaiketana"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Akatony"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr "Alefaso any amin'i"
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr "Jereo ny antsipiriany"
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Esory io namana io"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Pio, Vonoy"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Miala sehatra"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr ""
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr "Asehoy ny sora-drindra"
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr "Ajanony"
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr "Asehoy ny atiny"
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(toerana_malalaka)d MB Malalaka"
+
+#: ../src/jarabe/view/palettes.py:218
+msgid "Unmount"
+msgstr "Esory"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr ""
diff --git a/shell/po/mi.po b/shell/po/mi.po
new file mode 100644
index 0000000..a45bff2
--- /dev/null
+++ b/shell/po/mi.po
@@ -0,0 +1,979 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-27 13:34-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:26
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:59
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:68
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:90
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:99
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:114
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:130
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:145
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:168
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:176
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:183
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:195
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:19
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:32
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:56
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:64
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:77
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:93
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:102
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:115
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:123
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:133
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:56
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:153
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:40
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:104
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:109
+#: ../src/jarabe/desktop/meshbox.py:246
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:113
+#: ../extensions/deviceicon/network.py:166
+#: ../src/jarabe/desktop/meshbox.py:252
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:126
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:141
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:169
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:46
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:128
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:131
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:50
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:196
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:205
+#: ../src/jarabe/frame/zoomtoolbar.py:42
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:212
+msgid "Document"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:226
+#: ../src/jarabe/journal/objectchooser.py:141
+msgid "Close"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:272
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:273
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:276
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281 ../src/jarabe/desktop/homebox.py:113
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:111
+#: ../src/jarabe/frame/activitiestray.py:683
+#: ../src/jarabe/frame/activitiestray.py:762
+#: ../src/jarabe/frame/activitiestray.py:790
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:334
+msgid "Ok"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:114
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:196
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:341
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:408
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:449
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:329
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:666
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:67
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:69
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73 ../src/jarabe/frame/clipboardmenu.py:62
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:76
+#: ../src/jarabe/journal/journaltoolbox.py:357
+#: ../src/jarabe/journal/palettes.py:97 ../src/jarabe/view/palettes.py:127
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:106
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:107
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:116
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:233
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:234
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:296
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:297
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:304
+msgid "Resume by default"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:130
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:134
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:440
+#: ../src/jarabe/frame/activitiestray.py:707
+#: ../src/jarabe/journal/journaltoolbox.py:425
+#: ../src/jarabe/journal/palettes.py:63 ../src/jarabe/view/palettes.py:62
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:445
+#: ../src/jarabe/frame/activitiestray.py:221
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:18
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:35
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:40
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:226
+#: ../src/jarabe/frame/activitiestray.py:655
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:608
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:610
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:612
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:629
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:640
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:673
+#: ../src/jarabe/frame/activitiestray.py:780
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:751
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:47
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:36
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:38
+msgid "Group"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:40
+msgid "Home"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/collapsedentry.py:243
+#: ../src/jarabe/journal/expandedentry.py:159
+#: ../src/jarabe/journal/palettes.py:57
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:205
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:224
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:247
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:273
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:65
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:124
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:141
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:271
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:347
+#: ../src/jarabe/journal/palettes.py:81
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:66 ../src/jarabe/view/palettes.py:111
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:40
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:41
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:369
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:136
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:64
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:67
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:89
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:167
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:172
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:200
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:202
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:61
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:64
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:81
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:86
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:91
+msgid "Restart"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:96
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:131
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:43
+msgid "Starting..."
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:73
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:145
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:149
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:201
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:223 ../src/jarabe/view/palettes.py:272
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:248
+msgid "Unmount"
+msgstr ""
diff --git a/shell/po/mk.po b/shell/po/mk.po
new file mode 100644
index 0000000..4f5a51f
--- /dev/null
+++ b/shell/po/mk.po
@@ -0,0 +1,432 @@
+# translation of olpc-sugar.master.po to Macedonian
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Arangel Angov <arangel@linux.net.mk>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: olpc-sugar.master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2007-08-08 15:40+0200\n"
+"Last-Translator: Arangel Angov <arangel@linux.net.mk>\n"
+"Language-Team: Macedonian <ossm-members@hedona.on.net.mk>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "Име:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "Кликни да смениш боја:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Назад"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "Завршено"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "Напред"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "Отстрани пријател"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "Додај пријател"
+
+#. FIXME check that the buddy is not in the activity already
+#: ../shell/view/BuddyMenu.py:96
+msgid "Invite"
+msgstr "Покани"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "Отстрани"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "Отвори"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "Додај во дневникот"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Објект од таблата со исечоци: %s"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "Соседство"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "Група"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "Дома"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "Активност"
+
+#: ../services/clipboard/objecttypeservice.py:32
+msgid "Text"
+msgstr "Текст"
+
+#: ../services/clipboard/objecttypeservice.py:36
+msgid "Image"
+msgstr "Слика"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "Слика од екранот"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "Исклучи"
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "Соседство"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "Мојата батерија"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "Батеријата се полни"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "Батерјате се празни"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "Батеријата е наполнета"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "Приватно"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "Мое соседство"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "Зачувај"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "Стоп"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s активност"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/ml.po b/shell/po/ml.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/ml.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/mn.po b/shell/po/mn.po
new file mode 100644
index 0000000..f48fbfb
--- /dev/null
+++ b/shell/po/mn.po
@@ -0,0 +1,1516 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-11 00:32-0500\n"
+"PO-Revision-Date: 2009-09-22 14:33-0400\n"
+"Last-Translator: Odontsetseg Bat-Erdene <obat-erdene@suffolk.edu>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: mn\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 1.2.1\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Миний тухай"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Та нэр оруулах шаардлагатай."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "зурагдах хэмжээ: өнгө=%s тодролт=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "зурагдах хэмжээ: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "дүүргэх: өнгө=%s тодролт=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "дүүргэх: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Сонгосон өнгийг солиход алдаа гарлаа."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Сонгосон өнгөнд алдаа гарлаа."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "Нэр:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Товшиж өнгөө солино уу:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Миний компьютерийн тухай"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Боломжгүй байна"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Онцлох шинж"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Цувралын дугаар:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Програм хангамж"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Хувилбар:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Огноо ба Цаг"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Алдаа: цагийн бүс байхгүй байна."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:33
+msgid "Timezone"
+msgstr "Цагийн бүс"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Жааз"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Тоо хэмжээ нь бүхэл байх ёстой."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "хэзээ ч үгүй"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "эгшин зуур"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s секунд"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Идэвхжилтийн хоцролт"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Булан"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Ирмэг"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Хэл"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "~/.i18n хандаж чадсангүй. Үндсэн тохиргоог үүсгэнэ үү."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Кодны хэл=%s тодорхойлж чадсангүй."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Уучлаарай би '%s' хэлээр ярьдаггүй."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/view.py:90
+msgid "Username:"
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/view.py:101
+msgid "Password:"
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/view.py:112
+msgid "Number:"
+msgstr ""
+
+#: ../extensions/cpsection/modemconfiguration/view.py:123
+msgid "APN:"
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Сүлжээ"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Төлөв тодорхойгүй."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Сонгосон тохиргооны төлөвд алдаа гарлаа."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Сонгосон тохиргооны төлөвд алдаа гарлаа 0/1 aшиглах хэрэгтэй."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Утасгүй холболт"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Радио"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Хамтын ажиллагаа"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Сервер:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Хүчдэл"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Автомат үүсгүүр зохицуулалтын төлөвд алдаа гарлаа."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Хэт үүсгүүр зохицуулалтын төлөвд алдаа гарлаа."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Хүчдэл зохицуулагч"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Хүчдэлийг автоматаар зохицуулагч (батерейг хэмнэх)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Хүчдэлийг дээд зэргээр хэмнэх (радио долгионыг хааснаар батерейг хэмнэх)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Хангамж шинэчлэх"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "Огт үгүй"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Миний батарей"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Устгасан"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Цэнэглэгдэж байна"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Цэнэг маш бага байна"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d үлдлээ"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Цэнэглэгдсэн"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "IP хаяг: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:111
+msgid "Disconnect..."
+msgstr "Салгах..."
+
+#: ../extensions/deviceicon/network.py:116
+msgid "Create new wireless network"
+msgstr ""
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:122
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/desktop/meshbox.py:248 ../src/jarabe/desktop/meshbox.py:537
+msgid "Connecting..."
+msgstr "Холбогдож байна..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:126
+#: ../extensions/deviceicon/network.py:198
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:254 ../src/jarabe/desktop/meshbox.py:543
+msgid "Connected"
+msgstr "Холбогдсон"
+
+#: ../extensions/deviceicon/network.py:158
+msgid "Channel"
+msgstr "Суваг"
+
+#: ../extensions/deviceicon/network.py:173
+msgid "Wired Network"
+msgstr "Утастай Сүлжээ"
+
+#: ../extensions/deviceicon/network.py:201
+msgid "Speed"
+msgstr "Хурд"
+
+#: ../extensions/deviceicon/network.py:228
+msgid "Wireless modem"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:276
+msgid "Please wait..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:279
+#: ../src/jarabe/desktop/meshbox.py:164 ../src/jarabe/desktop/meshbox.py:494
+msgid "Connect"
+msgstr "Холбох"
+
+#: ../extensions/deviceicon/network.py:280
+msgid "Disconnected"
+msgstr "Салгагдсан"
+
+#: ../extensions/deviceicon/network.py:283
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "Болих"
+
+#: ../extensions/deviceicon/network.py:287
+#: ../src/jarabe/desktop/meshbox.py:168
+msgid "Disconnect"
+msgstr "Салгах"
+
+#: ../extensions/deviceicon/network.py:530
+#, python-format
+msgid "%s's network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:597
+#: ../extensions/deviceicon/network.py:656
+msgid "Mesh Network"
+msgstr "Тархалтын сүлжээ"
+
+#: ../extensions/deviceicon/network.py:857
+#, python-format
+msgid "Data sent %d kb / received %d kb"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:868
+msgid "Connection time "
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Миний чанга яригч"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Дуутай болгох"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Дуугүй болгох"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "Тархалт"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Бүлэг"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Нүүр хуудас"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Үйл ажиллагаа"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "Дэлгэцний зураг"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Default font face"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font size"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default nick"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+#, fuzzy
+msgid "Font face that is used throughout the desktop."
+msgstr "Хэрэглэгчийн нэр олон байдалд ашиглаж байдаг."
+
+#: ../data/sugar.schemas.in.h:14
+#, fuzzy
+msgid "Font size that is used throughout the desktop."
+msgstr "Хэрэглэгчийн нэр олон байдалд ашиглаж байдаг."
+
+#: ../data/sugar.schemas.in.h:15
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Jabber Server"
+msgstr "Жаббер Сервер"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Show Log out"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:32
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:36
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:37
+msgid "User Color"
+msgstr "Хэрэглэгчийн Өнгө"
+
+#: ../data/sugar.schemas.in.h:38
+msgid "User Name"
+msgstr "Хэрэглэгчийн Нэр"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "User name that is used throughout the desktop."
+msgstr "Хэрэглэгчийн нэр олон байдалд ашиглаж байдаг."
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Volume Level"
+msgstr "Дууны Хэмжээ"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Volume level for the sound device."
+msgstr "Дуу авианы тоноглолын дууны жэмжээ."
+
+#: ../data/sugar.schemas.in.h:42
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr "sugar-удирдах-самбар: АНХААР, нэр давхцаж байна: %s модуль: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-удирдах-самбар: товч=%s сонгох боломжгүй"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-удирдах-самбар: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,&amp;amp;amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;&amp;amp;amp;lt;br /&amp;amp;amp;gt;&amp;amp;lt;br /&amp;amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Хэрэглээ: sugar-удирдах-самбар [ сонголт ] товч [ аргумент ... ] \n"
+" Sugar-ийн орчны хяналт. \n"
+" Сонголтууд: \n"
+" -х Энэ тусламжын мэдээ үзүүлэх ба гаргах \n"
+" -л Боломжит сонголтын үзүүлэлтүүд \n"
+" -х товч Товчны тухай мэдээлэл \n"
+" -а товч Товчны одоогийн ач холбогдлыг мэдэх \n"
+" -ы товч Товчны одоогийн ач холбогдлыг тохируулах \n"
+" -с товч Товчны одоогийн ач холбогдлыг арилгах \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Өөрчлөлтийг идэвхжүүлэхийн тулд та дахин эхлүүлэх шаардлагатай.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "Анхаар"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Өөрчлөхийн тулд дахин эхлүүлэх хэрэгтэй"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "Өөрчлөлтийг цуцлах"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Дараа"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "Одоо эхлүүлэх үү"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "Боллоо"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "Тийм"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "Арилгахыг зөвшөөрөх"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Арилгахыг зөвшөөрөх: Та %s бүр мөсөн арилгахыг хүсч байна уу?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Хадгалах"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:105
+msgid "Erase"
+msgstr "Арилгах"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "Дуртай зүйлийг устгах"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "Дуртай зүйл болгох"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Дурын хэлбэр"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Цагираг"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Спираль"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Хайрцаг"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Гурвалжин"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "Бүртгэл бүтэлгүйтлээ"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "Бүртгэл амжилттай"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "Та одоо сургуулийн серверт бүртгэгдлээ."
+
+#: ../src/jarabe/desktop/favoritesview.py:630
+msgid "Register"
+msgstr "Бүртгүүлэх"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Хангамж Шинэчлэх"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Жагсаалтыг харах"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Дуртай зүйлсийг үзэх"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "Үндсэн төрөл:"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "Нэвтрэх нууцлалын төрөл:"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:492
+#, python-format
+#, fuzzy
+msgid "Mesh Network %d"
+msgstr "Тархалтын сүлжээ"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:629
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:65 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "Эргэж орох"
+
+#: ../src/jarabe/desktop/meshbox.py:634
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "Нэгдэх"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "Үл зөвшөөрөх"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "%s-ны %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "%r-аас дамжуулах"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "Зөвшөөрөх"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "%r-д дамжуулах"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "Устгах"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "Нээх"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "Сонгож нээх"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Хөршүүд"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "Энд дарж өнгөө солино уу:"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Буцах"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "Дараах"
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:59
+msgid "Untitled"
+msgstr "Гарчиггүй"
+
+#: ../src/jarabe/journal/expandedentry.py:243
+msgid "No preview"
+msgstr "Урьдчилан харах боломжгүй"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:262
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:286 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "Огноо байхгүй"
+
+#: ../src/jarabe/journal/expandedentry.py:293
+msgid "Participants:"
+msgstr "Гүйцэтгэгчид:"
+
+#: ../src/jarabe/journal/expandedentry.py:316
+msgid "Description:"
+msgstr "Тайлбар:"
+
+#: ../src/jarabe/journal/expandedentry.py:341
+msgid "Tags:"
+msgstr "Шошго:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Журнал"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Хайлт"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "Ямар ч үед"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Өнөөдөр"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Өчигдрөөс хойших"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Өнгөрсөн долоо хоногт"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Өнгөрсөн сард"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Өнгөрсөн жил"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Хэн ч гэсэн"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Миний найзууд"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Манай анги"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Бүх юм"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:83
+msgid "Copy"
+msgstr "Хуулах"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:68
+msgid "Start"
+msgstr "Эхлэх"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "Таны Журнал хоосон байна"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "Тохирсон оролт алга"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "Хайлт арилгах"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Таны Журнал дүүрэн байна"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Журнал Үзүүлэх"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Обьектыг сонгох"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Хаах"
+
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:91
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:100
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:178
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:183
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:211
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:213
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Найзыг хасах"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Найз нэмэх"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Унтраах"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Гарах"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "Миний Тохиргоо"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "%s-д урих"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Эхэлж байна..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "Зогсоох"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "Агуулгийг үзэх"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB ашиглаагүй"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#~ msgid "Document"
+#~ msgstr "Бичиг баримт"
+
+#~ msgid "No matching entries "
+#~ msgstr "Тохирсон оролт алга "
+
+#~ msgid "Restart"
+#~ msgstr "Дахин эхлүүлэх"
+
+#~ msgid "Unmount"
+#~ msgstr "Салгах"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Нууцлалын төрөл:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid "Disconnecting..."
+#~ msgstr "Салгагдаж байна..."
+
+#~ msgid "About my XO"
+#~ msgstr "Миний ХО-гын тухай"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Сургуулийн тархалтын порталд холбогдлоо."
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Сургуулийн тархалтын порталыг хайж байна ..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "XO-ын тархалтын порталд холбогдлоо"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "XO нэгдсэн порталыг хайж байна ..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Энгийн тархалтын сүлжээнд холбогдлоо"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Энгийн тархалтын сүлжээ эхэлж байна"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Үл мэдэгдэх тархалтын сүлжээ"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Самбарын санасан зүйлс: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "Сервер оруулах шаардлагатай."
+
+#~ msgid "Control Panel"
+#~ msgstr "Удирдах Самбар"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "off"
+#~ msgstr "Үгүй"
+
+#~ msgid "on"
+#~ msgstr "Тийм"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr ""
+#~ "Зөвшөөрөгдсөнгүй. Үүнийг ажиллуулахын тулд та root эрхтэй байх хэрэгтэй."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "Цагийн бүсийг уншихад алдаа гарлаа"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Цагийн бүсийг хуулахад алдаа гарлаа (%s-с): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Цагийн бүсийн зөвшөөрлийг өөрчлөх: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "Энэ компьютерын тухай"
+
+#~ msgid "Add to journal"
+#~ msgstr "Бүртгэлийн дэвтэрт нэмэх"
+
+#~ msgid "Reboot"
+#~ msgstr "Дахин ачаалах"
+
+#~ msgid "My Battery life"
+#~ msgstr "Миний цэнэгний хугацаа"
+
+#~ msgid "Battery charging"
+#~ msgstr "Зайг цэнэглэж байна"
+
+#~ msgid "Battery discharging"
+#~ msgstr "Зай цэнэгээ алдаж байна"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Зай дүүрэн цэнэглэгдлээ"
+
+#~ msgid "Share with:"
+#~ msgstr "Хуваалцах:"
+
+#~ msgid "Private"
+#~ msgstr "Хувийн"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "Миний хөршүүд"
+
+#~ msgid "Undo"
+#~ msgstr "Болих"
+
+#~ msgid "Redo"
+#~ msgstr "Давтах"
+
+#~ msgid "Paste"
+#~ msgstr "Хуулж тавих"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s ажил"
+
+#~ msgid "Keep error"
+#~ msgstr "Хадгалахад алдаа гарлаа"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "Хадгалахад алдаа гарлаа: бүх өөрчлөлтүүд устана"
+
+#~ msgid "Don't stop"
+#~ msgstr "Бүү зогсоо"
+
+#~ msgid "Stop anyway"
+#~ msgstr "Шууд хаах"
+
+#~ msgid "Continue"
+#~ msgstr "Үргэлжлүүлэх"
+
+#~ msgid "OK"
+#~ msgstr "ЗА"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "% жил"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "% жил"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "% сар"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "% сар"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "% долоо хоног"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "% долоо хоног"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "% өдөр"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "% өдөр "
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "% цаг"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "% цаг"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "% минут"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "% минут"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "% секунд"
+
+#~ msgid " and "
+#~ msgstr "ба"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#, python-format
+#~ msgid ", "
+#~ msgstr ","
diff --git a/shell/po/mr.po b/shell/po/mr.po
new file mode 100644
index 0000000..7ae554d
--- /dev/null
+++ b/shell/po/mr.po
@@ -0,0 +1,651 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-07-23 07:44-0400\n"
+"PO-Revision-Date: 2008-07-07 03:15-0400\n"
+"Last-Translator: Sandesh Patil <patil.sandesh@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "नाव"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "रंग बदलण्यासाठी क्लिक करा"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr "मागे"
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "पूर्ण करा"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "पूढे"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "मित्राला काढून टाका"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "मित्रा करा"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "%s ला आमंत्रण द्या"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "काढून टाकणे"
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "उघडणे"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63 ../src/view/home/HomeBox.py:86
+msgid "Keep"
+msgstr "संभाला"
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr "ने उघडा"
+
+#: ../src/view/clipboardmenu.py:216
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "क्‍लिपबॉअर्डची वस्तू:%s"
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "कळ प्रकार"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "पमाणिकरणचा प्रकार"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "गोपीनियचे प्रकार"
+
+#: ../src/view/Shell.py:240
+msgid "Screenshot"
+msgstr "पडदा चित्रा"
+
+#: ../src/view/home/HomeBox.py:80
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:82
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:89 ../src/view/palettes.py:120
+msgid "Erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:215
+msgid "List view"
+msgstr "यादी दृष्य"
+
+#: ../src/view/home/HomeBox.py:216
+#, fuzzy
+msgid "<Ctrl>2"
+msgstr "<ctr>L"
+
+#: ../src/view/home/HomeBox.py:273
+msgid "Favorites view"
+msgstr "आवडते दृश्‍ा"
+
+#: ../src/view/home/HomeBox.py:274
+#, fuzzy
+msgid "<Ctrl>1"
+msgstr "<ctr>L"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:282
+msgid "Freeform"
+msgstr "पासून मुक्त"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:289
+msgid "Ring"
+msgstr "रिंग"
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "संपर्क साधा"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "संपर्क तोडा"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "संपर्क तुटत आहे"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr "संपर्क होत आहे"
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr "संपर्क जुळले"
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr "मेष जाळे"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:119
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr "संपर्क तोडने"
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:61
+msgid "Resume"
+msgstr "पुन्हा आरंभ करणे"
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:205
+msgid "Join"
+msgstr "सामील व्हा"
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr "माज़ी बॅटरी"
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr "चार्ज होत आहे"
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr "थोडाकाच पावर उरला आहे"
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d उरले आहे"
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr "चार्ज झाले"
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr "माझे स्पीकर"
+
+#: ../src/view/devices/speaker.py:119
+msgid "Unmute"
+msgstr "आवज़ चालू"
+
+#: ../src/view/devices/speaker.py:122
+msgid "Mute"
+msgstr "आवज़ बंद"
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr "संपर्क तुटणे"
+
+#: ../src/view/devices/network/wireless.py:137
+msgid "Channel"
+msgstr "मार्ग"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "शेजार"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "गट"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "घर"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "क्रिया"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"शुगर - कंट्रोल - पॅनेल: सूचना, एकनावाचे एकापेक्षा जास्त विकल्प मिळाले: %s "
+"मॉडयुल: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "शुगर-कंट्रोल-पॅनेल:की=%s पर्याय उपलब्ध नाही"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "शुगर-कंट्रोल-पॅनेल:%s"
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"वापर:शुगर-कंट्रोल-पॅनेल[पर्याय]किल्ली[तर्क .....] \n"
+" शुगर वातावरणचे नियंत्रण. \n"
+" पर्याय: \n"
+" -h_ हा मदतीचा संदेश पाठवा आणि बंद करा \n"
+" -l_ उपलब्ध सूची दाखवा \n"
+" -h_ ह्या किल्लीबद्दल माहिती दाखवा -g किल्ली_ "
+" किल्लीची सध्याची किंमत घ्या \n"
+" -s किल्ली_ किल्लीला सध्याची किंमत द्या \n"
+"\t"
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "तुम्ही केलेले बदल लागू करण्यासाठी शुगर परत चालू करा.\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "रद्द करणे"
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:294
+msgid "Ok"
+msgstr "ठीक"
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:260
+msgid "Changes require restart"
+msgstr "बदली लागू करण्यासाठी परत सुरू करा"
+
+#: ../src/controlpanel/gui.py:259
+msgid "Warning"
+msgstr "सूचना"
+
+#: ../src/controlpanel/gui.py:263
+msgid "Cancel changes"
+msgstr "बदली रद्द करा"
+
+#: ../src/controlpanel/gui.py:267
+msgid "Later"
+msgstr "नंतर"
+
+#: ../src/controlpanel/gui.py:271
+msgid "Restart now"
+msgstr "परत सुरू करा"
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr "तुम्ही नाव टाकला पाहिजे"
+
+#: ../src/controlpanel/model/aboutme.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "stroke: color=%s hue=%s"
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr "stroke: %s"
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "fill: color=%s hue=%s"
+
+#: ../src/controlpanel/model/aboutme.py:76
+#, python-format
+msgid "fill: %s"
+msgstr "fill: %s"
+
+#: ../src/controlpanel/model/aboutme.py:87
+msgid "Error in specified color modifiers."
+msgstr "दिल्या गेलेल्या रंग रुपांतरच्या वर्णनात चुक आहे "
+
+#: ../src/controlpanel/model/aboutme.py:90
+msgid "Error in specified colors."
+msgstr "दिलेल्या रंगामध्ये चुक आहे"
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "उपलब्ध नाही"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr "चुक:वेळक्षेत्र अस्तित्वात नाही"
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr "किमान पूर्णांक असला पाहिजे"
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "प्रवेश नाही %s.योग्य सेटिंग बनवा."
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "कोडसाठी भाषा=%s अस्तित्वात नाही"
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "माफ करा मी %s बोलू शकत नाही"
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr "तुम्ही सर्वर टाकला पाहिजे"
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr "स्थिती अद्यात आहे"
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr "दिलेल्या रेडिओ सारांशमध्ये चुक आहे, चालू/बंद वापरा"
+
+#: ../src/controlpanel/model/power.py:57
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/model/power.py:86
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr "माज़ा बद्दल"
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr "रंग बदलण्यासाठी क्लिक करा"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr "माज़ा एक्सओ बद्दल"
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr "ओळख"
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr "क्रमशः क्रमांक"
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr "सॉफ्टवेर"
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr "बिल्ड :"
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr "फर्मवेर :"
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr "तारीख आणि वेळ"
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr "समयक्षेत्र"
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr "रचना"
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr "कधीच नाही"
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr "एकाच वेळी घडणारा"
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr "%s सेकेंड"
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr "चालू करण्यात होणारा उशीर"
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr "कोपरा"
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr "धार"
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr "भाषा"
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr "जाळ"
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr "विनतार "
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr "रेडियो"
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr "मेष"
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr "सर्वर :"
+
+#: ../src/controlpanel/view/power.py:27
+msgid "Power"
+msgstr ""
+
+#: ../src/controlpanel/view/power.py:51
+msgid "Power management"
+msgstr ""
+
+#: ../src/controlpanel/view/power.py:61
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/view/power.py:89
+msgid ""
+"Extreme power management (disables wireless radio, increases battery life)"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr "स्कूल मेष पोर्टला जोडत आहे"
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr " स्कूल मेष पोर्टला शोधत आहे"
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr "xo मेष पोर्टला जोडत आहे"
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr "xo मेष पोर्टला शोधत आहे"
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr "साधारण मेषला जोडत आहे"
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr "साधारण मेष चालू होत आहे"
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr "अनोळखी मेष"
+
+#: ../src/view/frame/activitiestray.py:210
+msgid "Decline"
+msgstr "अस्वीकार"
+
+#: ../src/view/home/favoritesview.py:285
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:286
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:288
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:289
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:405
+msgid "Control Panel"
+msgstr "कंट्रोल पॅनेल "
+
+#: ../src/view/home/favoritesview.py:416
+msgid "Restart"
+msgstr "पुन्हा चालू करा"
+
+#: ../src/view/home/favoritesview.py:421
+msgid "Shutdown"
+msgstr "बंद करा"
+
+#: ../src/view/home/favoritesview.py:427
+msgid "Register"
+msgstr "नोंद"
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr "चालू करणे"
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr "थांबा"
+
+#: ../src/view/palettes.py:104
+msgid "Start"
+msgstr "चालू करा"
+
+#: ../src/view/palettes.py:132
+msgid "Remove favorite"
+msgstr " आवडते काढून टाका"
+
+#: ../src/view/palettes.py:136
+msgid "Make favorite"
+msgstr " आवडते नोंद करा"
+
+#: ../src/view/palettes.py:185
+msgid "Show contents"
+msgstr "आतला दाखवा"
+
+#: ../src/view/palettes.py:209
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB फ्री"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<ctr>R"
+
+#~ msgid "Ring view"
+#~ msgstr "वर्तुळ दृष्य"
+
+#~ msgid "Remove from ring"
+#~ msgstr "वर्तुळा मधून काढा"
+
+#~ msgid "Add to ring"
+#~ msgstr "वर्तुळा मधे जोडा "
+
+#~ msgid "off"
+#~ msgstr "बंद"
+
+#~ msgid "on"
+#~ msgstr "चालू"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "परवानगी नाही. या पद्धतीचा वापर करण्यासाठी तुम्ही रूट असणे आवश्यक आहे"
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "वेळशेत्राच्या माहिती मध्ये चुकी आहे"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "वेळक्षेत्रेची नक्कल करण्यात चुक(%s पासून):%s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "वेळक्षेत्रेची परवानगी बदलली जात आहे:%s"
+
+#~ msgid "About this XO"
+#~ msgstr "एक्सो बद्दल"
+
+#~ msgid "Add to journal"
+#~ msgstr "नियतकालिका मध्ये समावेश करा"
+
+#~ msgid "Reboot"
+#~ msgstr "परत चालू करा"
+
+#~ msgid "My Battery life"
+#~ msgstr "माझ्या बॅटरीचे आयुष्य"
+
+#~ msgid "Battery charging"
+#~ msgstr "बॅटरी चाजॅ होत आहे"
+
+#~ msgid "Battery discharging"
+#~ msgstr "बॅटरीचे आयुष्य कमी होत आहे"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "बॅटरी पूर्ण चार्ज झाली"
diff --git a/shell/po/ms.po b/shell/po/ms.po
new file mode 100644
index 0000000..93c6b6e
--- /dev/null
+++ b/shell/po/ms.po
@@ -0,0 +1,958 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-31 00:30-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:26
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:59
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:68
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:90
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:99
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:114
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:130
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:145
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:168
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:176
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:183
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:195
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:19
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:32
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:56
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:64
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:77
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:93
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:102
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:115
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:123
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:133
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:56
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:153
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:40
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:104
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:109
+#: ../src/jarabe/desktop/meshbox.py:246
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:113
+#: ../extensions/deviceicon/network.py:166
+#: ../src/jarabe/desktop/meshbox.py:252
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:126
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:141
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:169
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:46
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:128
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:131
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:50
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:196
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:205
+#: ../src/jarabe/frame/zoomtoolbar.py:42
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:212
+msgid "Document"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:226
+#: ../src/jarabe/journal/objectchooser.py:141
+msgid "Close"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:272
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:273
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:276
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281 ../src/jarabe/desktop/homebox.py:113
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:111
+#: ../src/jarabe/frame/activitiestray.py:683
+#: ../src/jarabe/frame/activitiestray.py:762
+#: ../src/jarabe/frame/activitiestray.py:790
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:334
+msgid "Ok"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:114
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:196
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:341
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:408
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:449
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:329
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:666
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:67
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:69
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73 ../src/jarabe/frame/clipboardmenu.py:62
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:76
+#: ../src/jarabe/journal/journaltoolbox.py:357
+#: ../src/jarabe/journal/palettes.py:112 ../src/jarabe/view/palettes.py:127
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:106
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:107
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:116
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:233
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:234
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:296
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:297
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:304
+msgid "Resume by default"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:130
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:134
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:440
+#: ../src/jarabe/frame/activitiestray.py:707
+#: ../src/jarabe/journal/journaltoolbox.py:425
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:62
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:445
+#: ../src/jarabe/frame/activitiestray.py:221
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:18
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:35
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:40
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:226
+#: ../src/jarabe/frame/activitiestray.py:655
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:608
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:610
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:612
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:629
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:640
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:673
+#: ../src/jarabe/frame/activitiestray.py:780
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:751
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:47
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:36
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:38
+msgid "Group"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:40
+msgid "Home"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/collapsedentry.py:258
+#: ../src/jarabe/journal/expandedentry.py:159
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:205
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:224
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:247
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:273
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:65
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:124
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:141
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:271
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:347
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:75 ../src/jarabe/view/palettes.py:111
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:40
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:41
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:369
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:136
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:61
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:64
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:81
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:86
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:91
+msgid "Restart"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:96
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:131
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:43
+msgid "Starting..."
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:73
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:145
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:149
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:201
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:223 ../src/jarabe/view/palettes.py:272
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:248
+msgid "Unmount"
+msgstr ""
diff --git a/shell/po/mvo.po b/shell/po/mvo.po
new file mode 100644
index 0000000..e184567
--- /dev/null
+++ b/shell/po/mvo.po
@@ -0,0 +1,517 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:147
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:40
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr ""
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
diff --git a/shell/po/nb.po b/shell/po/nb.po
new file mode 100644
index 0000000..a96a394
--- /dev/null
+++ b/shell/po/nb.po
@@ -0,0 +1,621 @@
+# translation of sugar.po to Norsk bokmål
+# Kent Dahl <kentda@pvv.org>, 2008.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+msgid ""
+msgstr ""
+"Project-Id-Version: sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-07-16 00:30-0400\n"
+"PO-Revision-Date: 2008-07-26 13:31+0200\n"
+"Last-Translator: Kent Dahl <kentda@pvv.org>\n"
+"Language-Team: Norsk bokmål <i18n-no@lister.ping.uio.no>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/intro.py:65
+#: ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "Navn:"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "Klikk her for å endre farge"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr "Tilbake"
+
+#: ../src/intro/intro.py:159
+#: ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "Ferdig"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "Neste"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "Fjern venn"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "Bli venn"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "Inviter til %s"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "Fjern"
+
+#: ../src/view/clipboardmenu.py:53
+#: ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "Åpne"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+#: ../src/view/home/HomeBox.py:86
+msgid "Keep"
+msgstr "Behold"
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr "Åpne med"
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+#, fuzzy, python-format
+msgid "Clipboard object: %s."
+msgstr "Utklipp: %s"
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "Nøkkelform:"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "Autentiseringsform:"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "Krypteringsform:"
+
+#: ../src/view/Shell.py:235
+#, fuzzy
+msgid "Screenshot"
+msgstr "Skjermbilde"
+
+#: ../src/view/home/HomeBox.py:80
+msgid "Confirm erase"
+msgstr "Bekreft sletting"
+
+#: ../src/view/home/HomeBox.py:82
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Bekreft sletting: Ønsker du å slette %s for godt?"
+
+#: ../src/view/home/HomeBox.py:89
+#: ../src/view/palettes.py:120
+msgid "Erase"
+msgstr "Slett"
+
+#: ../src/view/home/HomeBox.py:215
+msgid "List view"
+msgstr "Listevisning"
+
+#: ../src/view/home/HomeBox.py:216
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:273
+#, fuzzy
+msgid "Favorites view"
+msgstr "Favoritvisning"
+
+#: ../src/view/home/HomeBox.py:274
+msgid "<Ctrl>1"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:282
+#, fuzzy
+msgid "Freeform"
+msgstr "Frihånd"
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:289
+msgid "Ring"
+msgstr "Ring"
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "Koble til"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "Koble fra"
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "Kobler fra..."
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr "Kobler til..."
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr "Tilkoblet"
+
+#: ../src/view/home/MeshBox.py:211
+#: ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+#, fuzzy
+msgid "Mesh Network"
+msgstr "Maskenettverk"
+
+#: ../src/view/home/MeshBox.py:214
+#: ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr "Koble fra..."
+
+#: ../src/view/home/MeshBox.py:302
+#: ../src/view/palettes.py:61
+msgid "Resume"
+msgstr "Gjenoppta"
+
+#: ../src/view/home/MeshBox.py:307
+#: ../src/view/frame/activitiestray.py:205
+msgid "Join"
+msgstr "Bli med"
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr "Mitt Batteri"
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr "Lader"
+
+#: ../src/view/devices/battery.py:114
+#, fuzzy
+msgid "Very little power remaining"
+msgstr "Veldig lite strøm igjen"
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+#, fuzzy, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d gjenstår"
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr "Oppladet"
+
+#: ../src/view/devices/speaker.py:41
+msgid "My Speakers"
+msgstr "Mine Høytalere"
+
+#: ../src/view/devices/speaker.py:116
+#, fuzzy
+msgid "Unmute"
+msgstr "Ikke demp"
+
+#: ../src/view/devices/speaker.py:119
+msgid "Mute"
+msgstr "Demp"
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr "Avkoblet"
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr "Kanal"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "Nabolag"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "Gruppe"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "Hjem"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "Lek"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: ADVARSEL, fant mer enn en opsjon med samme navnet: %s "
+"modul: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s er ikke en tilgjengelig opsjon."
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+# Remember to fix indenting.
+#: ../src/controlpanel/cmd.py:33
+#, fuzzy
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"Bruk: sugar-control-panel [ opsjon ] nøkkel [ argumenter ... ] \n"
+" Kontrollerer sugar-miljøet. \n"
+" Opsjoner: \n"
+" -h vis denne hjelpen og avsluttt \n"
+" -l lister alle tilgjengelig opsjoner \n"
+" -h nøkkel vis informasjon om denne nøkkelen \n"
+" -g nøkkel hent verdien til denne nøkkelen \n"
+" -s nøkkel sett denne nøkkelen sin verdi \n"
+" "
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "For å gjennomføre endringene må du starte sugar på nytt.\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "Avbryt"
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:34
+#: ../src/controlpanel/gui.py:260
+msgid "Changes require restart"
+msgstr "Endringer krever omstart"
+
+#: ../src/controlpanel/gui.py:259
+msgid "Warning"
+msgstr "Advarsel"
+
+#: ../src/controlpanel/gui.py:263
+msgid "Cancel changes"
+msgstr "Avbryt endringer"
+
+#: ../src/controlpanel/gui.py:267
+msgid "Later"
+msgstr "Senere"
+
+#: ../src/controlpanel/gui.py:271
+msgid "Restart now"
+msgstr "Start om nå"
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr "Du må skrive inn et navn."
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+#, fuzzy
+msgid "Error in specified color modifiers."
+msgstr "Feil i de angitte fargemodifikatorene."
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr "Feil i de angitte fargene."
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "Ikke tilgjengelig"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr "Feil: Tidssonen finnes ikke."
+
+#: ../src/controlpanel/model/frame.py:38
+#: ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr "Verdien må være et heltall."
+
+#: ../src/controlpanel/model/language.py:28
+#, fuzzy
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Fikk ikke tilgang til ~/.i18n. Lag standardinnstillinger."
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+#, fuzzy, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Kunne ikke fastslå språket for koden=%s."
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Beklager, jeg snakker ikke '%s'."
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr "Du må angi en tjener."
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr "Tilstanden er ukjent."
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/model/power.py:57
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Feil i argument til automatisk strømstyring, bruk on/off."
+
+#: ../src/controlpanel/model/power.py:86
+#, fuzzy
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Feil i argument til ekstrem strømstyring, bruk on/off."
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr "Om meg"
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr "Klikk for å endre din farge:"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr "Om min XO"
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr "Identitet"
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr "Serienummer:"
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr "Programvare"
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr "Bygg:"
+
+#: ../src/controlpanel/view/aboutxo.py:103
+#, fuzzy
+msgid "Firmware:"
+msgstr "Fastvare:"
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr "Dato og tid"
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr "Tidssone"
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr "Ramme"
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr "aldri"
+
+#: ../src/controlpanel/view/frame.py:31
+#, fuzzy
+msgid "instantaneous"
+msgstr "umiddelbar"
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr "%s sekunder"
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr "Aktiveringsforsinkelse"
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr "Hjørne"
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr "Kant"
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr "Språk"
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr "Nettverk"
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr "Trådløs"
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr "Radio:"
+
+# Maskenett
+#: ../src/controlpanel/view/network.py:94
+#, fuzzy
+msgid "Mesh"
+msgstr "Maskenett"
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr "Tjener:"
+
+#: ../src/controlpanel/view/power.py:27
+msgid "Power"
+msgstr "Strøm"
+
+#: ../src/controlpanel/view/power.py:51
+msgid "Power management"
+msgstr "Strømstyring"
+
+#: ../src/controlpanel/view/power.py:61
+msgid "Automatic power management (increases battery life)"
+msgstr "Automatisk strømstyring (øker batterilevetiden)"
+
+#: ../src/controlpanel/view/power.py:89
+#, fuzzy
+msgid ""
+"Extreme power management (disables wireless radio, increases battery life)"
+msgstr "Ekstrem strømstyring (slår av trådløs radio, øker batterilevetiden)"
+
+#: ../src/view/devices/network/mesh.py:108
+#, fuzzy
+msgid "Connected to a School Mesh Portal"
+msgstr "Koblet til en skolemaskenettportal"
+
+#: ../src/view/devices/network/mesh.py:110
+#, fuzzy
+msgid "Looking for a School Mesh Portal..."
+msgstr "Leter etter en skolemaskenettportal"
+
+#: ../src/view/devices/network/mesh.py:113
+#, fuzzy
+msgid "Connected to an XO Mesh Portal"
+msgstr "Koblet til en XO maskenett portal"
+
+#: ../src/view/devices/network/mesh.py:115
+#, fuzzy
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Leter etter en XO maskenett portal..."
+
+#: ../src/view/devices/network/mesh.py:118
+#, fuzzy
+msgid "Connected to a Simple Mesh"
+msgstr "Koblet til et enkelt maskenett"
+
+#: ../src/view/devices/network/mesh.py:120
+#, fuzzy
+msgid "Starting a Simple Mesh"
+msgstr "Starter et enkelt maskenett"
+
+#: ../src/view/devices/network/mesh.py:127
+#, fuzzy
+msgid "Unknown Mesh"
+msgstr "Ukjent maskenett"
+
+#: ../src/view/frame/activitiestray.py:210
+msgid "Decline"
+msgstr "Avslå"
+
+#: ../src/view/home/favoritesview.py:285
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:286
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:288
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:289
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:379
+msgid "Control Panel"
+msgstr "Kontrollpanel"
+
+#: ../src/view/home/favoritesview.py:390
+msgid "Restart"
+msgstr "Omstart"
+
+#: ../src/view/home/favoritesview.py:395
+msgid "Shutdown"
+msgstr "Slå av"
+
+#: ../src/view/home/favoritesview.py:401
+msgid "Register"
+msgstr "Registrer"
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr "Starter..."
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr "Stans"
+
+#: ../src/view/palettes.py:104
+msgid "Start"
+msgstr "Start"
+
+#: ../src/view/palettes.py:132
+msgid "Remove favorite"
+msgstr "Fjern favoritt"
+
+#: ../src/view/palettes.py:136
+#, fuzzy
+msgid "Make favorite"
+msgstr "Lagre som favoritt"
+
+#: ../src/view/palettes.py:185
+msgid "Show contents"
+msgstr "Vis innhold"
+
+#: ../src/view/palettes.py:209
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB ledig"
diff --git a/shell/po/ne.po b/shell/po/ne.po
new file mode 100644
index 0000000..dd2c9a7
--- /dev/null
+++ b/shell/po/ne.po
@@ -0,0 +1,1267 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-06-11 00:31-0400\n"
+"PO-Revision-Date: 2009-07-27 00:08-0400\n"
+"Last-Translator: Daniel Drake <dsd@laptop.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: ne\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 1.2.1\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "मेरो बारेमा"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "तिमीले नाम हाल्नै पर्छ।"
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "ब्रसको धर्को: रङ्ग=%s ह्‍यु‍=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "ब्रसको धर्का: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "भर: रङ्ग=%s ह्‍यु=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "भर: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "तोकिएको रङ्ग परिमार्जकहरुमा त्रुटी छ।"
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "तोकिएको रङ्गहरुमा त्रुटी छ।"
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "नामः"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "रङ्ग परिवर्तन गर्न क्लिक गरः"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "मेरो कम्पयूटरको बारेमा"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "उपलब्ध छैन"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "व्यक्तित्ब"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "क्रमिक अङ्क"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "सफ्टवेर"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "बनाइ:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "सुगर:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "फर्मवेर:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "तारबिनाको फर्मवेर:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "कपिराइट र अनुमतिपत्र"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"अहिले तपाईंले हेरिराखेको ग्रफीकल युजर इन्टरफेस सुगर हो। सुगर फ्री सफ्टवेर "
+"हो, सुगर ले जि एन यु जनरल पब्लिक अनुमति पत्र प्रयोग गर्छ र तपाईंले यसलाई "
+"परिवर्तन गरेर नियम अनुसार अरुलाई दिन सक्नुहुन्छ।"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "सम्पूर्ण अनुमति पत्र:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "मिती & समय"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "त्रुटि, समयक्षेत्र उपलब्ध छैन।"
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:19
+msgid "Timezone"
+msgstr "समयक्षेत्र"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "चौखट"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "गुण संख्या हुनु पर्छ।"
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "कहिलेपनि नगर"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "तात्कालिक"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s सेकेण्ड"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "सुरु गर्न ढिलाइ"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "कुना"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "कुना"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:32
+msgid "Language"
+msgstr "भाषा"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "~/.i18n. मा पहुँच भएन। मानक सेटिङ्गहरु बनाऊ।"
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "कोड=%sको भाषा निश्चित गर्न सकिएन।"
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "माफ गर्नुस, म '%s' बोल्दिन।"
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "सञ्जाल"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "अवस्था अज्ञात छ।"
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "तोकिएको रेडियो निर्देशनमा त्रुटि छ, बन्द/खुला प्रयोग गर।"
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "तोकिएको निर्देशनमा त्रुटि छ, 0/1 प्रयोग गर।"
+
+#: ../extensions/cpsection/network/view.py:56
+msgid "Wireless"
+msgstr "तार विना"
+
+#: ../extensions/cpsection/network/view.py:64
+msgid "Turn off the wireless radio to save battery life"
+msgstr "ब्याटरि बचाउन तारबिनाको रेडियो बन्द गर्नुहोस।"
+
+#: ../extensions/cpsection/network/view.py:77
+msgid "Radio"
+msgstr "रेडियो"
+
+#: ../extensions/cpsection/network/view.py:93
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "सञ्जालमा जोष्न समस्या भए सञ्जालको ईतिहास मेट्नुहोस्"
+
+#: ../extensions/cpsection/network/view.py:102
+msgid "Discard network history"
+msgstr "सञ्जालको ईतिहास मेट्ने"
+
+#: ../extensions/cpsection/network/view.py:115
+msgid "Collaboration"
+msgstr "सहकार्य"
+
+#: ../extensions/cpsection/network/view.py:123
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"सर्भर भनेको तिमी बसेको कोठा जस्तो हो, ‍एउटै सर्भरमा भएका XO हरु एक अर्कालाई "
+"देख्न सक्छन्, एउटै नेटवर्कमा नहुन्दा पनि।"
+
+#: ../extensions/cpsection/network/view.py:133
+msgid "Server:"
+msgstr "सर्भर"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "शक्ति"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "आफैँ चल्ने pm निर्देशनमा त्रुटि छ, बन्द/खुला प्रयोग गर।"
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "अन्तिम रुपको pm निर्देशनमा त्रुटि छ, बन्द/खुला प्रयोग गर।"
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "शक्तिको प्रभन्धकर्ता"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "आफैँ चल्ने शक्तिको प्रबन्धकर्ता (ब्याटरिको जीवन बढाउँछ)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"अति किफायत शक्तिको प्रबन्धकर्ता (तार बिनाको रेडियो असमर्थ पार्छ, ब्याटरिको "
+"जीवन बढाउँछ)"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "मेरो बेटरी"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "हट्यो"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "चार्ज हुँदैछ"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "एकदमै थोरै शक्‍ति बाँकी छ"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d बाँकी"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "चार्ज भयो"
+
+#: ../extensions/deviceicon/network.py:43
+#, python-format
+msgid "IP address: %s"
+msgstr "आइपी अड्रेस: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:109
+msgid "Disconnect..."
+msgstr "जडान विच्छेद..."
+
+#: ../extensions/deviceicon/network.py:113
+msgid "Create new wireless network"
+msgstr ""
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:119
+#: ../src/jarabe/desktop/meshbox.py:250
+msgid "Connecting..."
+msgstr "जडान हुदैछ..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:123
+#: ../extensions/deviceicon/network.py:179
+#: ../src/jarabe/desktop/meshbox.py:256
+msgid "Connected"
+msgstr "जडान भयो"
+
+#: ../extensions/deviceicon/network.py:139
+msgid "Channel"
+msgstr "माध्यम"
+
+#: ../extensions/deviceicon/network.py:154
+msgid "Wired Network"
+msgstr "तार युक्त संजाल"
+
+#: ../extensions/deviceicon/network.py:182
+msgid "Speed"
+msgstr "गति"
+
+#: ../extensions/deviceicon/network.py:389
+#, python-format
+msgid "%s's network"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "मेरो स्पिकरहरु"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "आवाज खोल"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "आवाज बन्द"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr "मेश"
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:38
+msgid "Group"
+msgstr "समुह"
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:40
+msgid "Home"
+msgstr "गृह"
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:42
+msgid "Activity"
+msgstr "क्रियाकलाप"
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr "पर्दाछवि"
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr "बैकअप URL"
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"XO आईकनको रंग जुन डेस्कटप भरि प्रयोग गरिन्छ । स्ट्रिङ्ग स्ट्रोक रंग र फिल "
+"रंगले बनेको हो, फर्म्याट rbg रंगको हुन्छ। उदाहरण: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr "फ्रेम आउन ढिलाइ"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr "कनँर प्रयोग गरेर ढांचाको सक्रियतालाई ढिलाइ गर्ने।"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr "उद्विग्न प्रयोग गरेर ढांचाको सक्रियतालाई ढिलाइ गर्ने।"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr "उद्विग्न ढिलाइ"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr "मनपर्दो रूपरेखा"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr "मनपर्दो पुनरारम्भ विधा"
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"यदि सही हो भने, सुगरले हामिलाई अरु ज्याबर सर्भरको अरु युजरहरुले खोज्न मिल्छ।"
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Jabber Server"
+msgstr "ज्याबर सर्भर"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Layout of the favorites view."
+msgstr "मनपर्दो दर्श्यको रूपरेखा।"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Power Automatic"
+msgstr "स्वचालित शक्ती"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Power Automatic."
+msgstr "स्वचालित शक्ती."
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Power Extreme"
+msgstr "अत्यधिक शक्ती"
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Power Extreme."
+msgstr "अत्यधिक शक्ती."
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Publish to Gadget"
+msgstr "यन्त्रमा प्रकाशित गर"
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Setting for muting the sound device."
+msgstr "ध्वनि यन्त्रको आवाज बन्द गर्ने सेटिङ्ग।"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Sound Muted"
+msgstr "आवाज बन्द"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Timezone setting for the system."
+msgstr "यस सिस्टमको समय अंचल सेटिङ्ग।"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Url of the jabber server to use."
+msgstr "ज्याबर सर्भर चलाउनको लागि चाहिने Url"
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Url where the backup is saved to."
+msgstr "ब्याकप बचत गर्ने ठाउँको Url"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "User Color"
+msgstr "युजरको रङ्ग"
+
+#: ../data/sugar.schemas.in.h:24
+msgid "User Name"
+msgstr "युजरको नाम"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "User name that is used throughout the desktop."
+msgstr "डेस्कटपभरि प्रयोग हुने युजरको नाम।"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Volume Level"
+msgstr "आवाज सतह"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Volume level for the sound device."
+msgstr "आवाज सतह यन्त्रको लागि।"
+
+#: ../data/sugar.schemas.in.h:28
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"पुनरारम्भ मोडमा भएको बेलामा कृपापात्रमा क्लिक गरेमा क्रियाकलापको अन्तिम "
+"प्रविष्टि पुनरारम्भ हुन्छ।"
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"सुगर-कन्ट्रोल-प्यानल: सावधान, त्यही नाम भएको एउटा भन्दा धेरै रोजाई भेटियो: %"
+"s मोडियुल: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "सुगर-कन्ट्रोल-प्यानल: key=%s उपलब्ध छैन"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "सुगर-कन्ट्रोल-प्यानल: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"प्रयोग: सुगर-कन्ट्रोल-प्यानल [ option ] कि [ args ... ] \n"
+" सुगर वातावरणको लागी कन्ट्रोल।\n"
+" Option: \n"
+" -h यो सहयोग सन्देश देखाउ र निस्क \n"
+" -l भएका सबै सेवाहरु सुचिमा देखाउ \n"
+" -h कि यो कि सम्बन्धि जानकारी देखाउ \n"
+" -g कि किको अहिलेको मान लिउ \n"
+" -s कि किको लागी अहिलेको मान राख \n"
+" -c कि किको लागी अहिलेको मान सफा गर \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "परिवर्तन लागू गर्न सुगर पुन:शुरु गर्नु पर्छ । \n"
+
+#: ../src/jarabe/controlpanel/gui.py:275
+msgid "Warning"
+msgstr "सावधान"
+
+#: ../src/jarabe/controlpanel/gui.py:276
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "परिवर्तनका लागी पुण: सुरु गर्न आवश्यक छ"
+
+#: ../src/jarabe/controlpanel/gui.py:279
+msgid "Cancel changes"
+msgstr "परिवर्तनहरु रद्द गर"
+
+#: ../src/jarabe/controlpanel/gui.py:284 ../src/jarabe/desktop/homebox.py:113
+msgid "Later"
+msgstr "पछी"
+
+#: ../src/jarabe/controlpanel/gui.py:288
+msgid "Restart now"
+msgstr "पुन: सुरु गर"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "भयो"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:111
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:821
+#: ../src/jarabe/frame/activitiestray.py:849
+msgid "Cancel"
+msgstr "रद्द"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:339
+msgid "Ok"
+msgstr "हुन्छ"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "स्वतन्त्र आकारको"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "औँठी"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:334
+msgid "Spiral"
+msgstr "पेंचदार"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:401
+msgid "Box"
+msgstr "बाकस"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:442
+msgid "Triangle"
+msgstr "त्रिकोण"
+
+#: ../src/jarabe/desktop/favoritesview.py:330
+msgid "Registration Failed"
+msgstr "दर्ता असफल भयो"
+
+#: ../src/jarabe/desktop/favoritesview.py:331
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Registration Successful"
+msgstr "दर्ता सफल"
+
+#: ../src/jarabe/desktop/favoritesview.py:334
+msgid "You are now registered with your school server."
+msgstr "अब तपाईँको नाम बिद्यालयको सर्भरमा दर्ता भइसक्यो।"
+
+#: ../src/jarabe/desktop/favoritesview.py:674
+msgid "Register"
+msgstr "दर्ता"
+
+#: ../src/jarabe/desktop/homebox.py:67
+msgid "Confirm erase"
+msgstr "साँच्चै मेट्ने"
+
+#: ../src/jarabe/desktop/homebox.py:69
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "साँच्छै मेट्ने: %s लाई सधैँको लागी मेट्न चहान्छौ?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/homebox.py:73 ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "राख"
+
+#: ../src/jarabe/desktop/homebox.py:76
+#: ../src/jarabe/journal/journaltoolbox.py:357
+#: ../src/jarabe/journal/palettes.py:112 ../src/jarabe/view/palettes.py:153
+msgid "Erase"
+msgstr "मेट"
+
+#: ../src/jarabe/desktop/homebox.py:106
+msgid "Software Update"
+msgstr "सॉफ्टवेयर आधुनिकीकरण"
+
+#: ../src/jarabe/desktop/homebox.py:107
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "नया सफ्टवेर चलाउनका निमीत्त तिम्रो क्रियाकलापहरु अप्डेट गर"
+
+#: ../src/jarabe/desktop/homebox.py:116
+msgid "Check now"
+msgstr "अहिले जाँच गर"
+
+#: ../src/jarabe/desktop/homebox.py:233
+msgid "List view"
+msgstr "सुची दृश्य"
+
+#: ../src/jarabe/desktop/homebox.py:234
+msgid "<Ctrl>2"
+msgstr "<Ctrl>२"
+
+#: ../src/jarabe/desktop/homebox.py:296
+msgid "Favorites view"
+msgstr "मन्पर्दो दृश्य"
+
+#: ../src/jarabe/desktop/homebox.py:297
+msgid "<Ctrl>1"
+msgstr "<Ctrl>१"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr "कुञ्जी प्रकार:"
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr "प्रमाणीकरण प्रकार:"
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr "WPA र WPA2 निजी"
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr "तारबिनाको लागि सुरक्षा"
+
+#: ../src/jarabe/desktop/meshbox.py:134
+msgid "Connect"
+msgstr "जोड"
+
+#: ../src/jarabe/desktop/meshbox.py:138
+msgid "Disconnect"
+msgstr "विच्छेद भयो"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:449
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:425
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:66
+msgid "Resume"
+msgstr "पुनरारम्भ"
+
+#: ../src/jarabe/desktop/meshbox.py:454
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr "सहभागी होऊ"
+
+#: ../src/jarabe/desktop/schoolserver.py:34
+msgid "Cannot obtain data needed for registration."
+msgstr "रजिस्टरको लागि चाइने तथ्याङ्क प्राप्त गर्न सकिएन।"
+
+#: ../src/jarabe/desktop/schoolserver.py:51
+msgid "Cannot connect to the server."
+msgstr "सर्भरमा जड़ान हुन सकेन।"
+
+#: ../src/jarabe/desktop/schoolserver.py:56
+msgid "The server could not complete the request."
+msgstr "सर्भरले अनुरोध पुरा गर्न सकेन।"
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr "नाई"
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr "%s को %s"
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr "%r बाट सार्नुहोस"
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr "स्विकार"
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:839
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:873
+msgid "Dismiss"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr "%r मा सार्नुहोस"
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr "हटाऊ"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "खोल"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "साथ खोल"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s क्लिपिङ"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:36
+msgid "Neighborhood"
+msgstr "छिमेक"
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "रङ्ग परिवर्तन गर्न क्लिक गरः"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "पछाडि"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "अर्को"
+
+#: ../src/jarabe/journal/collapsedentry.py:258
+#: ../src/jarabe/journal/expandedentry.py:159
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "बिना शिर्षक"
+
+#: ../src/jarabe/journal/expandedentry.py:205
+msgid "No preview"
+msgstr "पूर्वावलोकन छैन"
+
+#: ../src/jarabe/journal/expandedentry.py:224
+msgid "Participants:"
+msgstr "भागिदारहरु"
+
+#: ../src/jarabe/journal/expandedentry.py:247
+msgid "Description:"
+msgstr "वर्णनः"
+
+#: ../src/jarabe/journal/expandedentry.py:273
+msgid "Tags:"
+msgstr "चिनोहरु:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "पंजिका"
+
+#: ../src/jarabe/journal/journaltoolbox.py:65
+msgid "Search"
+msgstr "खोज"
+
+#: ../src/jarabe/journal/journaltoolbox.py:124
+msgid "Anytime"
+msgstr "कुनैबेला"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Today"
+msgstr "आज"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Since yesterday"
+msgstr "हिजो देखि"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Past week"
+msgstr "गत हप्ता"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past month"
+msgstr "गत महिना"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past year"
+msgstr "गत वर्ष"
+
+#: ../src/jarabe/journal/journaltoolbox.py:141
+msgid "Anyone"
+msgstr "जो सुकै"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "My friends"
+msgstr "मेरा साथीहरु"
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "My class"
+msgstr "मेरो कक्षा"
+
+# TRANS: Item in a combo box that filters by entry type.
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:271
+msgid "Anything"
+msgstr "कुनैपनि"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:347
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "प्रतिलिपि"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:75 ../src/jarabe/view/palettes.py:135
+msgid "Start"
+msgstr "सुरु गर"
+
+#: ../src/jarabe/journal/listview.py:40
+msgid "Your Journal is empty"
+msgstr "तिम्रो पंजिका खाली छ"
+
+#: ../src/jarabe/journal/listview.py:41
+msgid "No matching entries "
+msgstr "मिल्ने लेखा छैन "
+
+#: ../src/jarabe/journal/listview.py:370
+msgid "Clear search"
+msgstr "खोजलाई सफा गर"
+
+#: ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "मिति छैन"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "तिम्रो पंजिका भरिएको छ"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr "क्रिपया कुनै पुरानो पंजिकाहरु हटाएर नया पंजिकाहरु को लागि ठाउ बनाउ।"
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "पंजिका देखाउ"
+
+#: ../src/jarabe/journal/objectchooser.py:147
+msgid "Choose an object"
+msgstr "वस्तु छान"
+
+#: ../src/jarabe/journal/objectchooser.py:152
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "बन्द"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr "पुनरारम्भ सहित"
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr "शुरु सहित"
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr "पठाउनु"
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr "वृत्तांत हेर"
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr "कुनै पनि साथीहरु हाजीर छैन"
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr "कुनै पनि सदर संयोग भेटिएन"
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr "पुनरारम्भ गर्न कुनै क्रियाकलाप छैन"
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr "सुरु गर्न कुनै क्रियाकलाप छैन"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "साथी हटाऊ"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "साथी बनाऊ"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "My Settings"
+msgstr "मेरो योजनाहरु"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "लगआउट"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "Restart"
+msgstr "पून: सुरु"
+
+#: ../src/jarabe/view/buddymenu.py:100
+msgid "Shutdown"
+msgstr "बन्द"
+
+#: ../src/jarabe/view/buddymenu.py:135
+#, python-format
+msgid "Invite to %s"
+msgstr "%s लाई निम्ता देऊ"
+
+#: ../src/jarabe/view/palettes.py:47
+msgid "Starting..."
+msgstr "शुरु हुदैछ..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:73
+msgid "View Source"
+msgstr "स्रोत हेर"
+
+#: ../src/jarabe/view/palettes.py:84
+msgid "Stop"
+msgstr "बन्द गर"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Remove favorite"
+msgstr "प्रिय हटाउ"
+
+#: ../src/jarabe/view/palettes.py:178
+msgid "Make favorite"
+msgstr "प्रिय बनाउ"
+
+#: ../src/jarabe/view/palettes.py:241
+msgid "Show contents"
+msgstr "वस्तुहरु देखाउ"
+
+#: ../src/jarabe/view/palettes.py:263 ../src/jarabe/view/palettes.py:313
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB खालि"
+
+#: ../src/jarabe/view/palettes.py:288
+msgid "Unmount"
+msgstr "हटाऊ"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "दृष्टांत मुल"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "मुल"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "क्रियाकलाप बन्डलको मुल"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "स्रोत हेर : %r"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© २००८ वान ल्यप् टप पर चाईल्ड असोसिएसन आइ एन सि; रेड ह्यट आइ एन सि; र अरु "
+#~ "निर्माताहरु।"
+
+#~ msgid "Document"
+#~ msgstr "कागतपत्र"
+
+#~ msgid "Resume by default"
+#~ msgstr "पुनरारम्भद्वारा बकाया"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "गुप्तीकरण प्रकार:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#, fuzzy
+#~ msgid "Disconnecting..."
+#~ msgstr "जडान विच्छेद"
+
+#~ msgid "Mesh Network"
+#~ msgstr "मेश सञ्जाल"
+
+#~ msgid "Disconnected"
+#~ msgstr "विच्छेद भयो"
+
+#~ msgid "About my XO"
+#~ msgstr "मिरो XO बारे"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "विद्यालय मेश पोर्टलमा जडान भयो"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "विद्यालय मेश पोर्टल खोज्दै..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "XO मेश पोर्टलमा जडान भयो"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "XO मेश पोर्टल खोज्दै..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "साधारण मेशमा जडान भयो"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "साधारण मेश शुरु गर्दै"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "अज्ञात मेश"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "क्लिपपाटी वस्तु: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "तिमिले सर्भर हाल्नु पर्छ"
+
+#~ msgid "Control Panel"
+#~ msgstr "नियन्त्रण चौकोस"
+
+#~ msgid "off"
+#~ msgstr "बन्द"
+
+#~ msgid "on"
+#~ msgstr "खुला"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "अनुमति दिईएन। यो काम गर्न तिमी रुट हुनुपर्छ।"
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "समयक्षेत्र पढ्दा त्रुटि भयो"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "समयक्षेत्र प्रतिलिपि गर्दा त्रुटि भयो (%s बाट): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "%s समयक्षेत्रको अनुमति परिवर्तन गर्दै "
+
+#~ msgid "About this XO"
+#~ msgstr "यो XO को बारेमा"
+
+#~ msgid "Add to journal"
+#~ msgstr "खातामा राख"
+
+#~ msgid "Reboot"
+#~ msgstr "बन्द गरि फेरि खोल"
+
+#~ msgid "My Battery life"
+#~ msgstr "मेरो बेटरी"
+
+#~ msgid "Battery charging"
+#~ msgstr "बेटरी चार्ज हुँदै"
+
+#~ msgid "Battery discharging"
+#~ msgstr "बेटरी सकिदै छ"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "बेटरीमा पूरा चार्ज छ"
+
+#~ msgid "Share with:"
+#~ msgstr "साझा गर:"
+
+#~ msgid "Private"
+#~ msgstr "निजी"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "मेरो छिमेक"
+
+#~ msgid "Undo"
+#~ msgstr "पूर्वस्थिति"
+
+#~ msgid "Redo"
+#~ msgstr "नयाँस्थिति"
+
+#~ msgid "Paste"
+#~ msgstr "टाँस"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s क्रियाकलाप"
+
+#~ msgid "Keep error"
+#~ msgstr "त्रुटि राख"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "त्रुटि राख: सवै परिवर्तनहरु हराउनेछन्"
+
+#~ msgid "Don't stop"
+#~ msgstr "नरोक"
+
+#~ msgid "Stop anyway"
+#~ msgstr "जसरी पनि रोक"
+
+#~ msgid "Continue"
+#~ msgstr "जारी राख"
+
+#~ msgid "OK"
+#~ msgstr "हुन्छ"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d वर्ष"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d वर्ष"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d महिना"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d महिना"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d हप्ता"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d हप्ता"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d दिन"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d दिन"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d घण्टा"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d घण्टा"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d मिनेट"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d मिनेट"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d सेकेण्ड"
+
+#~ msgid " and "
+#~ msgstr "_र_"
+
+#~ msgid ", "
+#~ msgstr ",_"
diff --git a/shell/po/nl.po b/shell/po/nl.po
new file mode 100644
index 0000000..bf437de
--- /dev/null
+++ b/shell/po/nl.po
@@ -0,0 +1,1556 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-06-08 00:31-0400\n"
+"PO-Revision-Date: 2010-08-07 21:55+0200\n"
+"Last-Translator: Myckel Habets <myckel@sdf.lonestar.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 2.0.3\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Over mij"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Je moet een naam invoeren."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "streep: kleur=%s tint=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "streep: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "vulling: kleur=%s tint=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "vulling: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Fout in opgegeven kleurenmodificaties."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Fout in opgegeven kleuren."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "Naam:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Klik om de kleur te veranderen:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Over mijn computer"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Niet beschikbaar"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Identiteit"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Serienummer:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Software"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Bouw:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "Firmware draadloos netwerk:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Copyright en licentie"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Sugar is de grafische gebruikersinterface waar je momenteel naar kijkt. "
+"Sugar is vrije software, uitgegeven onder de GNU General Public License, en "
+"je mag het aanpassen en/of kopieën distribueren onder de condities zoals "
+"vermeld in de licentie."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Volledige licentie:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Datum en Tijd"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Fout tijdzone bestaat niet."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:47
+msgid "Timezone"
+msgstr "Tijdzone"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Kader"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Waarde moet een geheel getal zijn."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "nooit"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "direct"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s seconden"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Activatievertraging"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Hoek"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Rand"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "Toetsenbord"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "Toetsenbordmodel"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "Toets(en) om de indeling te veranderen"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "Toetsenbordindeling(en)"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Taal"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Kon niet bij ~/.i18n komen. Standaard instellingen aanmaken."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Taal voor code=%s kon niet bepaald worden."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Sorry ik spreek geen '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"Voeg talen toe in de volgorde die je wenst. Als een vertaling niet "
+"beschikbaar is, zal de volgende in de lijst gebruikt worden."
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr "Modem configuratie"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:91
+msgid "Username:"
+msgstr "Gebruikersnaam:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:102
+msgid "Password:"
+msgstr "Wachtwoord:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:113
+msgid "Number:"
+msgstr "Getal:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:124
+msgid "Access Point Name (APN):"
+msgstr "Access Point Naam (APN):"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:135
+msgid "Personal Identity Number (PIN):"
+msgstr "Persoonlijk Identiteitsnummer (PIN):"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:146
+msgid "Personal Unblocking Key (PUK):"
+msgstr "Persoonlijke Ontsluitingssleutel (PUK):"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:167
+msgid ""
+"You will need to provide the following information to set up a mobile "
+"broadband connection to a cellular (3G) network."
+msgstr ""
+"Je moet de volgende informatie opgeven om een mobiele breedbandverbinding "
+"via een mobiel (3G) netwerk op te zetten."
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Netwerk"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Status is onbekend."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Fout in opgegeven keuze argument gebruik aan/uit."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Fout in opgegeven keuze argument gebruik 0/1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Draadloos"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Draadloze zender uitzetten om de batterij te besparen"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Zender"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+"Gooi de netwerkgeschiedenis weg als je problemen hebt om met het netwerk te "
+"verbinden"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Netwerkgeschiedenis weggooien"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Samenwerking"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"De server is hetzelfde als de ruimte waar jij je in bevindt; mensen op "
+"dezelfde server kunnen elkaar zien, ook als ze niet op hetzelfde netwerk "
+"zitten."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Server:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Energie"
+
+#: ../extensions/cpsection/power/model.py:85
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Fout in automatisch energiebeheer argument, gebruik on/off."
+
+#: ../extensions/cpsection/power/model.py:112
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Fout in extreem energiebeheer argument, gebruik on/off."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Energiebeheer"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Automatisch energiebeheer (verhoogt gebruiksduur accu)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Extreem energiebeheer (deactiveert draadloze zender, verhoogt gebruiksduur "
+"accu)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Software-update"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"Software-updates verbeteren fouten, verhelpen beveiligingsproblemen en "
+"bieden nieuwe mogelijkheden."
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "Controleren van %s..."
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "Downloaden van %s..."
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "Updaten van %s..."
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "Je software is bijgewerkt"
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "Je kan %s update installeren"
+msgstr[1] "Je kan %s updates installeren"
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "Controleren op updates..."
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "Updates installeren..."
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s update is geïnstalleerd"
+msgstr[1] "%s updates zijn geïnstalleerd"
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "Installatie geselecteerd"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "Downloadgrootte: %s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "Van versie %(current)d naar %(new)s (Grootte: %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "Niets"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1 KB"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f KB"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Mijn Accu"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Verwijderd"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Opladen"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Heel weinig energie over"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d over"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Opgeladen"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "IP adres: %s"
+
+#: ../extensions/deviceicon/network.py:112
+msgid "Disconnect..."
+msgstr "Verbinding verbreken..."
+
+#: ../extensions/deviceicon/network.py:117
+msgid "Create new wireless network"
+msgstr "Nieuw draadloos netwerk aanmaken"
+
+#: ../extensions/deviceicon/network.py:123
+#: ../extensions/deviceicon/network.py:285
+#: ../src/jarabe/desktop/meshbox.py:247 ../src/jarabe/desktop/meshbox.py:536
+msgid "Connecting..."
+msgstr "Verbinden..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:127
+#: ../extensions/deviceicon/network.py:199
+#: ../extensions/deviceicon/network.py:289
+#: ../src/jarabe/desktop/meshbox.py:253 ../src/jarabe/desktop/meshbox.py:542
+msgid "Connected"
+msgstr "Verbonden"
+
+#: ../extensions/deviceicon/network.py:159
+msgid "Channel"
+msgstr "Kanaal"
+
+#: ../extensions/deviceicon/network.py:174
+msgid "Wired Network"
+msgstr "Bedraad netwerk"
+
+#: ../extensions/deviceicon/network.py:202
+msgid "Speed"
+msgstr "Snelheid"
+
+#: ../extensions/deviceicon/network.py:229
+msgid "Wireless modem"
+msgstr "Draadloze modem"
+
+#: ../extensions/deviceicon/network.py:277
+msgid "Please wait..."
+msgstr "Even geduld aub..."
+
+#: ../extensions/deviceicon/network.py:280
+#: ../src/jarabe/desktop/meshbox.py:163 ../src/jarabe/desktop/meshbox.py:493
+msgid "Connect"
+msgstr "Verbinden"
+
+#: ../extensions/deviceicon/network.py:281
+msgid "Disconnected"
+msgstr "Verbinding verbroken"
+
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:708
+#: ../src/jarabe/frame/activitiestray.py:807
+#: ../src/jarabe/frame/activitiestray.py:835
+msgid "Cancel"
+msgstr "Annuleren"
+
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:167
+msgid "Disconnect"
+msgstr "Verbinding verbreken"
+
+#: ../extensions/deviceicon/network.py:292
+msgid "Sim requires Pin/Puk"
+msgstr "Sim vereist Pin/Puk"
+
+#: ../extensions/deviceicon/network.py:293
+msgid "Authentication Error"
+msgstr "Authenticatiefout"
+
+#: ../extensions/deviceicon/network.py:538
+#, python-format
+msgid "%s's network"
+msgstr "%s's netwerk"
+
+#: ../extensions/deviceicon/network.py:605
+#: ../extensions/deviceicon/network.py:664
+msgid "Mesh Network"
+msgstr "Mesh netwerk"
+
+#: ../extensions/deviceicon/network.py:869
+#, python-format
+msgid "Data sent %d KB / received %d KB"
+msgstr "Gegevens verstuurd %d KB / ontvangen %d KB"
+
+#: ../extensions/deviceicon/network.py:880
+msgid "Connection time "
+msgstr "Tijd verbonden "
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Mijn Speakers"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Ontdempen"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Dempen"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "Mesh"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Groep"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Thuis"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Activiteit"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "Schermafdruk"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "Schermafdruk van \"%s\""
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr ""
+"\"uitgezet\" om bijnaam te vragen bij initialisatie; \"systeem\" hergebruikt de "
+"UNIX gebruiker lange naam."
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Additional directories which can contain updated translations."
+msgstr "Additionele directories die bijgewerkte vertalingen kunnen bevatten."
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Backup URL"
+msgstr "Back-up URL"
+
+#: ../data/sugar.schemas.in.h:4
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"Kleur van het XO icoon dat op de desktop gebruikt word. De waarden bestaan "
+"uit een lijnkleur en een vulkleur, formaat is gelijk aan rbg kleuren. "
+"Bijvoorbeeld: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Corner Delay"
+msgstr "Hoekvertraging"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font face"
+msgstr "Standaard lettertype"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default font size"
+msgstr "Standaard lettergrootte"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Default nick"
+msgstr "Standaard bijnaam"
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the corners."
+msgstr "Vertraging voor de activatie van het kader door de hoeken te gebruiken."
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Vertraging voor de activatie van het kader door de randen te gebruiken."
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Directory to search for translations"
+msgstr "Directory om naar vertalingen te zoeken"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Edge Delay"
+msgstr "Randvertraging"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Favorites Layout"
+msgstr "Favorietenlayout"
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Favorites resume mode"
+msgstr "Favorieten hervatmodus"
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Font face that is used throughout the desktop."
+msgstr "Lettertype dat overal gebruikt wordt op het bureaublad."
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Font size that is used throughout the desktop."
+msgstr "Lettergrootte die overal gebruikt wordt op het bureaublad."
+
+#: ../data/sugar.schemas.in.h:17
+msgid "GSM network APN"
+msgstr "GSM netwerk APN"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "GSM network PIN"
+msgstr "GSM netwerk PIN"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "GSM network PUK"
+msgstr "GSM netwerk PUK"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "GSM network access point name configuration"
+msgstr "GSM netwerk access point naam configuratie"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "GSM network number"
+msgstr "GSM netwerknummer"
+
+#: ../data/sugar.schemas.in.h:22
+msgid "GSM network password"
+msgstr "GSM netwerkwachtwoord"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "GSM network password configuration"
+msgstr "GSM netwerkwachtwoord configuratie"
+
+#: ../data/sugar.schemas.in.h:24
+msgid "GSM network personal identification number configuration"
+msgstr "GSM netwerk persoonlijk identificatienummer configuratie"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "GSM network personal unlock key configuration"
+msgstr "GSM netwerk persoonlijk ontsluitsleutel configuratie"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "GSM network telephone number configuration"
+msgstr "GSM netwerk telefoonnummer configuratie"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "GSM network username"
+msgstr "GSM netwerkgebruikersnaam"
+
+#: ../data/sugar.schemas.in.h:28
+msgid "GSM network username configuration"
+msgstr "GSM netwerkgebruikersnaam configuratie"
+
+#: ../data/sugar.schemas.in.h:29
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"Indien WAAR, dan zal Sugar ons opzoekbaar maken voor andere gebruikers op de "
+"Jabber server."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "Indien WAAR, zal Sugar een \"Afmelden\" optie geven."
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Jabber Server"
+msgstr "Jabber-server"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "Keyboard layouts"
+msgstr "Toetsenbordindelingen"
+
+#: ../data/sugar.schemas.in.h:33
+msgid "Keyboard model"
+msgstr "Toetsenbordmodel"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Keyboard options"
+msgstr "Toetsenbordopties"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Layout of the favorites view."
+msgstr "Layout van de favorieten weergave."
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+"Lijst met toetsenbordindelingen. Elke invoer moet in de "
+"vormindeling(variant) zijn"
+
+#: ../data/sugar.schemas.in.h:37
+msgid "List of keyboard options."
+msgstr "Lijst met toetsenbordopties."
+
+#: ../data/sugar.schemas.in.h:38
+msgid "Power Automatic"
+msgstr "Energiebeheer: automatisch"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "Power Automatic."
+msgstr "Energiebeheer: automatisch."
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Power Extreme"
+msgstr "Energiebeheer: extreem"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Power Extreme."
+msgstr "Energiebeheer: extreem."
+
+#: ../data/sugar.schemas.in.h:42
+msgid "Publish to Gadget"
+msgstr "Publiceren naar gadget"
+
+#: ../data/sugar.schemas.in.h:43
+msgid "Setting for muting the sound device."
+msgstr "Instelling voor dempen van het audio-apparaat."
+
+#: ../data/sugar.schemas.in.h:44
+msgid "Show Log out"
+msgstr "Afmelden weergeven"
+
+#: ../data/sugar.schemas.in.h:45
+msgid "Sound Muted"
+msgstr "Geluid gedempt"
+
+#: ../data/sugar.schemas.in.h:46
+msgid "The keyboard model to be used"
+msgstr "Het toetsenbordmodel om te gebruiken"
+
+#: ../data/sugar.schemas.in.h:48
+msgid "Timezone setting for the system."
+msgstr "Tijdzone-instelling voor het systeem."
+
+#: ../data/sugar.schemas.in.h:49
+msgid "Url of the jabber server to use."
+msgstr "Url van de te gebruiken jabber-server."
+
+#: ../data/sugar.schemas.in.h:50
+msgid "Url where the backup is saved to."
+msgstr "Url waar de back-up opgeslagen wordt."
+
+#: ../data/sugar.schemas.in.h:51
+msgid "User Color"
+msgstr "Gebruikerskleur"
+
+#: ../data/sugar.schemas.in.h:52
+msgid "User Name"
+msgstr "Gebruikersnaam"
+
+#: ../data/sugar.schemas.in.h:53
+msgid "User name that is used throughout the desktop."
+msgstr "Gebruikersnaam die op de desktop gebruikt wordt."
+
+#: ../data/sugar.schemas.in.h:54
+msgid "Volume Level"
+msgstr "Volumeniveau"
+
+#: ../data/sugar.schemas.in.h:55
+msgid "Volume level for the sound device."
+msgstr "Volumeniveau voor het audio-apparaat."
+
+#: ../data/sugar.schemas.in.h:56
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"Indien in hervatmodus, kun je door te klikken op een favorietenicoon ervoor "
+"zorgen dat de laatste invoer van die activiteit hervat wordt."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-stuur-paneel: WAARSCHUWING, meer dan één optie met dezelfde naam "
+"gevonden: %s module: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: sleutel=%s is geen beschikbare optie"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-stuur-paneel: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Gebruik: sugar-stuur-paneel [ optie ] sleutel [ args ... ] \n"
+" Configuratie voor de sugar omgeving. \n"
+" Opties: \n"
+" -h geef dit helpbericht weer en sluit af \n"
+" -l lijst van alle beschikbare opties \n"
+" -h sleutel geef informatie over deze sleutel \n"
+" -g sleutel verkrijg de huidige waarde van de sleutel \n"
+" -s sleutel zet de huidige waarde naar de sleutel \n"
+" -c sleutel wis de huidige waarde van de sleutel \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Om je veranderingen toe te passen moet je sugar herstarten.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "Waarschuwing"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Verandering vereist een herstart"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "Veranderingen annuleren"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Later"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "Herstart nu"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "Klaar"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "Versie %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "Bevestig wissen"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Bevestig wissen: Wilt u permanent %s wissen?"
+
+# lijkt misschien teveel op een "sla op" actie?
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Bewaar"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:361
+#: ../src/jarabe/journal/palettes.py:106
+msgid "Erase"
+msgstr "Wissen"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "Verwijder favoriet"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "Maak favoriet"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Vrijevorm"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Ring"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Spiraal"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Vierkant"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Driehoek"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "Registratie mislukt"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "Registratie succesvol uitgevoerd"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "Je bent nu geregistreerd bij je school-server."
+
+#: ../src/jarabe/desktop/favoritesview.py:631
+msgid "Register"
+msgstr "Registreren"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Software Bijwerken"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"Update je activiteiten om zeker ervan te zijn dat ze met je nieuwe software "
+"compatibel zijn"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Controleer nu"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Lijstweergave"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Favorietenweergave"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "Sleutel type:"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "Authenticatie type:"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "WPA & WPA2 Persoonlijk"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "Draadloze netwerkbeveiliging:"
+
+#: ../src/jarabe/desktop/meshbox.py:491
+#, python-format
+msgid "Mesh Network %d"
+msgstr "Mesh Netwerk %d"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:628
+#: ../src/jarabe/frame/activitiestray.py:743
+#: ../src/jarabe/journal/journaltoolbox.py:440
+#: ../src/jarabe/journal/palettes.py:66 ../src/jarabe/view/palettes.py:79
+msgid "Resume"
+msgstr "Hervatten"
+
+#: ../src/jarabe/desktop/meshbox.py:633
+#: ../src/jarabe/frame/activitiestray.py:241
+msgid "Join"
+msgstr "Bijvoegen"
+
+#: ../src/jarabe/desktop/schoolserver.py:104
+msgid "Cannot connect to the server."
+msgstr "Kan niet met de server verbinden."
+
+#: ../src/jarabe/desktop/schoolserver.py:109
+msgid "The server could not complete the request."
+msgstr "De server kon de aanvraag niet voltooien."
+
+#: ../src/jarabe/frame/activitiestray.py:246
+#: ../src/jarabe/frame/activitiestray.py:680
+msgid "Decline"
+msgstr "Weigeren"
+
+#: ../src/jarabe/frame/activitiestray.py:632
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:634
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:636
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:653
+#, python-format
+msgid "%s of %s"
+msgstr "%s van %s"
+
+#: ../src/jarabe/frame/activitiestray.py:665
+#, python-format
+msgid "Transfer from %r"
+msgstr "Overdragen van %r"
+
+#: ../src/jarabe/frame/activitiestray.py:675
+msgid "Accept"
+msgstr "Accepteren"
+
+#: ../src/jarabe/frame/activitiestray.py:698
+#: ../src/jarabe/frame/activitiestray.py:825
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:732
+#: ../src/jarabe/frame/activitiestray.py:860
+msgid "Dismiss"
+msgstr "Wegdoen"
+
+#: ../src/jarabe/frame/activitiestray.py:795
+#, python-format
+msgid "Transfer to %r"
+msgstr "Overdragen naar %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:233
+msgid "Remove"
+msgstr "Verwijderen"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "Openen"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "Openen met"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s in klembord zetten"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Omgeving"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "Klik om de kleur te veranderen:"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Terug"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "Volgende"
+
+#: ../src/jarabe/journal/expandedentry.py:151
+#: ../src/jarabe/journal/palettes.py:60
+msgid "Untitled"
+msgstr "Naamloos"
+
+#: ../src/jarabe/journal/expandedentry.py:242
+msgid "No preview"
+msgstr "Geen voorbeeld"
+
+#: ../src/jarabe/journal/expandedentry.py:261
+#, python-format
+msgid "Kind: %s"
+msgstr "Type: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:261
+msgid "Unknown"
+msgstr "Onbekend"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Date: %s"
+msgstr "Datum: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Size: %s"
+msgstr "Grootte: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:285 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "Geen datum"
+
+#: ../src/jarabe/journal/expandedentry.py:292
+msgid "Participants:"
+msgstr "Deelnemers:"
+
+#: ../src/jarabe/journal/expandedentry.py:315
+msgid "Description:"
+msgstr "Omschrijving:"
+
+#: ../src/jarabe/journal/expandedentry.py:340
+msgid "Tags:"
+msgstr "Labels:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/journaltoolbox.py:411
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Dagboek"
+
+#: ../src/jarabe/journal/journaltoolbox.py:68
+msgid "Search"
+msgstr "Zoeken"
+
+#: ../src/jarabe/journal/journaltoolbox.py:127
+msgid "Anytime"
+msgstr "Ieder tijdstip"
+
+#: ../src/jarabe/journal/journaltoolbox.py:129
+msgid "Today"
+msgstr "Vandaag"
+
+#: ../src/jarabe/journal/journaltoolbox.py:131
+msgid "Since yesterday"
+msgstr "Sinds gisteren"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:133
+msgid "Past week"
+msgstr "Afgelopen week"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:135
+msgid "Past month"
+msgstr "Afgelopen maand"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:137
+msgid "Past year"
+msgstr "Afgelopen jaar"
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "Anyone"
+msgstr "Iedereen"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My friends"
+msgstr "Mijn vrienden"
+
+#: ../src/jarabe/journal/journaltoolbox.py:147
+msgid "My class"
+msgstr "Mijn klas"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:275
+msgid "Anything"
+msgstr "Alles"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:351
+#: ../src/jarabe/journal/palettes.py:84
+msgid "Copy"
+msgstr "Kopieer"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:443
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start"
+msgstr "Start"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "Je dagboek is leeg"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "Geen overeenkomende ingangen"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "Zoekopdracht wissen"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Je dagboek is vol"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr "Verwijder a.u.b. oude dagboekingangen om ruimte te maken voor nieuwe."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Dagboek weergeven"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Kies een object"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:310
+msgid "Close"
+msgstr "Sluiten"
+
+#: ../src/jarabe/journal/palettes.py:67
+msgid "Resume with"
+msgstr "Hervatten met"
+
+#: ../src/jarabe/journal/palettes.py:70
+msgid "Start with"
+msgstr "Starten met"
+
+#: ../src/jarabe/journal/palettes.py:92
+msgid "Send to"
+msgstr "Verstuur naar"
+
+#: ../src/jarabe/journal/palettes.py:101
+msgid "View Details"
+msgstr "Details weergeven"
+
+#: ../src/jarabe/journal/palettes.py:179
+msgid "No friends present"
+msgstr "Geen vrienden aanwezig"
+
+#: ../src/jarabe/journal/palettes.py:184
+msgid "No valid connection found"
+msgstr "Geen bruikbare verbinding gevonden"
+
+#: ../src/jarabe/journal/palettes.py:212
+msgid "No activity to resume entry"
+msgstr "Geen activiteit om invoer mee te hervatten"
+
+#: ../src/jarabe/journal/palettes.py:214
+msgid "No activity to start entry"
+msgstr "Geen activiteit om invoer mee te starten"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Verwijder vriend"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Maak vriend"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Afsluiten"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Afmelden"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "Mijn instellingen"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Nodig uit voor %s"
+
+#: ../src/jarabe/view/launcher.py:190
+#, python-format
+msgid "<b>%s</b> failed to start."
+msgstr "<b>%s</b> kon niet starten."
+
+#: ../src/jarabe/view/palettes.py:47
+msgid "Starting..."
+msgstr "Beginnen..."
+
+#: ../src/jarabe/view/palettes.py:57
+msgid "Activity failed to start"
+msgstr "Activiteit kon niet starten"
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:86
+msgid "View Source"
+msgstr "Bron weergeven"
+
+#: ../src/jarabe/view/palettes.py:97
+msgid "Stop"
+msgstr "Stop"
+
+#: ../src/jarabe/view/palettes.py:137
+msgid "Start new"
+msgstr "Begin nieuw"
+
+#: ../src/jarabe/view/palettes.py:186
+msgid "Show contents"
+msgstr "Inhoud weergeven"
+
+#: ../src/jarabe/view/palettes.py:208 ../src/jarabe/view/palettes.py:258
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB vrij"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Werkkopie van bron maken"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Bron"
+
+#: ../src/jarabe/view/viewsource.py:294
+msgid "Activity Bundle Source"
+msgstr "Activiteitsbundel Bron"
+
+#: ../src/jarabe/view/viewsource.py:301
+#, python-format
+msgid "View source: %r"
+msgstr "Bron weergeven: %r"
+
+#~ msgid "APN:"
+#~ msgstr "APN:"
+
+#~ msgid "Title"
+#~ msgstr "Titel"
+
+#~ msgid "Version"
+#~ msgstr "Versie"
+
+#~ msgid "Date"
+#~ msgstr "Datum"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr ""
+#~ "Kan vereiste gegevens die nodig zijn voor de registratie niet verkrijgen."
+
+#~ msgid "Unmount"
+#~ msgstr "Loskoppelen"
+
+#~ msgid "Restart"
+#~ msgstr "Herstarten"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; en anderen die "
+#~ "bijgedragen hebben."
+
+#~ msgid "Document"
+#~ msgstr "Document"
+
+#~ msgid "Resume by default"
+#~ msgstr "Standaard hervatten"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Encryptie type:"
+
+#~ msgid "Disconnecting..."
+#~ msgstr "Verbinding verbreken..."
+
+#~ msgid "About my XO"
+#~ msgstr "Over mijn XO"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Verbonden met een School Mesh Portaal"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Zoeken naar een School Mesh Portaal..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Verbonden met een XO Mesh Portaal"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "Zoeken naar een XO Mesh Portaal..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Verbinden met een Eenvoudige Mesh"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Start een Eenvoudige Mesh"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Onbekende Mesh"
+
+#~ msgid "Settings"
+#~ msgstr "Instellingen"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Klembord object: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "U moet een server opgeven."
+
+#~ msgid "Control Panel"
+#~ msgstr "Configuratiepaneel"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "Add to journal"
+#~ msgstr "Voeg toe aan dagboek"
+
+#~ msgid "Reboot"
+#~ msgstr "Herstart"
+
+#~ msgid "Share with:"
+#~ msgstr "Deel met:"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "Mijn Omgeving"
+
+#~ msgid "Undo"
+#~ msgstr "Maak ongedaan"
+
+#~ msgid "Redo"
+#~ msgstr "Doe opnieuw"
+
+#~ msgid "Paste"
+#~ msgstr "Plak"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s Activiteit"
+
+#~ msgid "Keep error"
+#~ msgstr "Bewaarfout"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "Bewaarfout: alle wijzigingen gaan verloren"
+
+#~ msgid "Don't stop"
+#~ msgstr "Niet stoppen"
+
+#~ msgid "Stop anyway"
+#~ msgstr "Toch stoppen"
+
+#~ msgid "Continue"
+#~ msgstr "Doorgaan"
+
+#~ msgid "OK"
+#~ msgstr "OK"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d jaar"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d jaren"
diff --git a/shell/po/pa.po b/shell/po/pa.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/pa.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/pap.po b/shell/po/pap.po
new file mode 100644
index 0000000..2523f6e
--- /dev/null
+++ b/shell/po/pap.po
@@ -0,0 +1,535 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: 2008-06-23 12:17-0400\n"
+"Last-Translator: Urso Wieske <uwieske@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "Nomber:"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "Klik pa kambia kolor:"
+
+#: ../src/intro/intro.py:145
+#, fuzzy
+msgid "Back"
+msgstr "Bek"
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "Kla"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "Sigiente"
+
+#: ../src/view/BuddyMenu.py:58
+#, fuzzy
+msgid "Remove friend"
+msgstr "Kita amigu"
+
+#: ../src/view/BuddyMenu.py:61
+#, fuzzy
+msgid "Make friend"
+msgstr "Hasi amigu"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "Invita pa %s"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "Elimina"
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "Habri"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr "Habri ku"
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Clipboard obgeto: %s."
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "Tip di Tecla"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "Tipo di Autentikashon"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "Tipo di Enkriptashon:"
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr "Kaptura di pantaya"
+
+#: ../src/view/home/HomeBox.py:147
+#, fuzzy
+msgid "List view"
+msgstr "Bista di lista"
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr "<CTRL>L"
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr "<Ctrl>R"
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "Konekta"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "Diskonekta"
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "Deskonektando..."
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr "Konektando..."
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr "Konektá"
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr "Deskonekta..."
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr "Resumí"
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr "Uni"
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr "Mi Bateria"
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr "Kargando"
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr "A sobra masha tiki power "
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "A sobra %(ora)d:%(min).2d "
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr "Kargá"
+
+#: ../src/view/devices/speaker.py:40
+#, fuzzy
+msgid "My Speakers"
+msgstr "Mi spikernan"
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr "Silensia"
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr "Deskonektá"
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr "Kanal"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "Besindario"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "Grupo"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "Home"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "Aktividad"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: KIDOU, a hanja mas ku un opshon ku e mesun nomber: %s "
+"modulo: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: klave=%s no ta un opshon disponibel"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+#: ../src/controlpanel/cmd.py:33
+#, fuzzy
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"Uso: sugar-control-panel [opshon] klave [argumentonan ...] \n"
+" Control pa e ambiente di sugar.\n"
+" Opshonnan: \n"
+" -h mustra e help mensahe aki i sali -l "
+" lista tur opshon disponibel\n"
+" -h klave mustra informashon riba e klave aki\n"
+" -g klave hanja e bolr koriente di e klave aki\n"
+" -s klave sèt e bolor koriente di klave aki\n"
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Pa aplika bo kambionan bo tin ku restart sugar di nobo.\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "Kansela"
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr "Kambionan ta eksigi restart"
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr "Kidou"
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr "Kansela kambionan"
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr "Despues"
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr "Restart aworaki"
+
+#: ../src/controlpanel/model/aboutme.py:44
+#, fuzzy
+msgid "You must enter a name."
+msgstr "Bo mester fill in un nomber."
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:48
+#, fuzzy
+msgid "You must enter a server."
+msgstr "Bo mester fill in un nomber."
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:134
+#, fuzzy
+msgid "Click to change your color:"
+msgstr "Klik pa kambia kolor:"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr ""
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
diff --git a/shell/po/pis.po b/shell/po/pis.po
new file mode 100644
index 0000000..e184567
--- /dev/null
+++ b/shell/po/pis.po
@@ -0,0 +1,517 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:147
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:40
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr ""
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
diff --git a/shell/po/pl.po b/shell/po/pl.po
new file mode 100644
index 0000000..a48e32e
--- /dev/null
+++ b/shell/po/pl.po
@@ -0,0 +1,485 @@
+# translation of pl.po to Polish
+# Piotr Drąg <raven@pmail.pl>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: pl\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2008-01-07 22:22+0000\n"
+"Last-Translator: Wiktor Idzikowski <wiktor.idzikowski@gmail.com>\n"
+"Language-Team: Polish <pl@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:77
+msgid "Pick a buddy picture"
+msgstr "Wybierz obrazek znajomego"
+
+#: ../shell/intro/intro.py:100
+msgid "My Picture:"
+msgstr "Mój obrazek:"
+
+#: ../shell/intro/intro.py:180
+msgid "My Name:"
+msgstr "Moje imię:"
+
+#: ../shell/intro/intro.py:224
+msgid "My Color:"
+msgstr "Mój kolor:"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "Usuń przyjaciela"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "Uczyń przyjacielem"
+
+#. FIXME check that the buddy is not in the activity already
+#: ../shell/view/BuddyMenu.py:96
+msgid "Invite"
+msgstr "Zaproś"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "Usuń"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "Otwórz"
+
+#: ../shell/view/clipboardmenu.py:76
+msgid "Stop download"
+msgstr "Zatrzymaj pobieranie"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "Dodaj do dziennika"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Obiekt w schowku: %s."
+
+#: ../services/clipboard/objecttypeservice.py:32
+msgid "Text"
+msgstr "Tekst"
+
+#: ../services/clipboard/objecttypeservice.py:36
+msgid "Image"
+msgstr "Obrazek"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "Zrzut ekranu"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "Zakończ"
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "Sieć"
+
+#: ../sugar/activity/activity.py:68
+msgid "Save"
+msgstr "Zapisz"
+
+#: ../sugar/activity/activity.py:74
+msgid "Share"
+msgstr "Podziel się"
+
+#: ../sugar/activity/activity.py:87
+msgid "Close"
+msgstr "Zamknij"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "Aktywność %s"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "Imię:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "Kliknij aby zmienić kolor:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Wstecz"
+
+#: ../shell/intro/intro.py:160
+#, fuzzy
+msgid "Done"
+msgstr "Zakończono"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "Dalej"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "Zaproś do %s"
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "Rodzaj klucza:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "Rodzaj uwierzytelniania:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "Rodzaj szyfrowania:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+#, fuzzy
+msgid "Starting..."
+msgstr "Rozpoczynanie..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "Wznów"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "Zatrzymaj"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "Uruchom ponownie"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "Zarejestruj"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+#, fuzzy
+msgid "Disconnect..."
+msgstr "Rozłączanie..."
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "Dołącz"
+
+#: ../shell/view/devices/battery.py:38
+#, fuzzy
+msgid "My Battery life"
+msgstr "Życie mojej baterii"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "Ładowanie baterii"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "Rozładowywanie baterii"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "Bateria w pełni naładowana"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "Rozłączony"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "Kanał"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "Sąsiedztwo"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "Grupa"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "Dom"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "Czynność"
+
+#: ../lib/sugar/activity/activity.py:115
+#, fuzzy
+msgid "Share with:"
+msgstr "Podziel się z:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "Prywatny"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "Moje sąsiedztwo"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "Zachowaj"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "Cofnij"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "Ponów"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "Kopiuj"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "Wklej"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "Zachowaj błąd"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "Zachowaj błąd: wszystkie zmiany zostaną utracone"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "Nie zatrzymuj"
+
+#: ../lib/sugar/activity/activity.py:831
+#, fuzzy
+msgid "Stop anyway"
+msgstr "Zatrzymaj mimo wszystko"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "Anuluj"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "Ok"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "Kontynuuj"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "OK"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d rok"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d lata"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d miesiąc"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d miesiące"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d tydzień"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d tygodnie"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d dzień"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+#, fuzzy
+msgid "%d days"
+msgstr "%d dni"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d godzina"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d godziny"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d minuta"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d minuty"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d sekunda"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d sekundy"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr "_i_"
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+#, fuzzy
+msgid ", "
+msgstr ", "
+
+#: ../shell/controlpanel/control.py:213
+#, fuzzy
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Aby zastosować zmiany należy uruchomić ponownie sugar."
+
+#: ../shell/controlpanel/control.py:267
+#, fuzzy
+msgid "Error in specified color modifiers."
+msgstr "Błąd w podanych modifikatorach kolorów."
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "Błąd w podanych kolorach."
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "Wyłączony"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "Włączony"
+
+#: ../shell/controlpanel/control.py:310
+#, fuzzy
+msgid "State is unknown."
+msgstr "Nieokreślony stan."
+
+#: ../shell/controlpanel/control.py:332
+#, fuzzy
+msgid "Error in specified radio argument use on/off."
+msgstr "Błąd w podanych arugumentach radia użyj Włącz/Wyłącz"
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr "Brak dostępu. Musisz być superużytkownikiem aby użyć tej metody."
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "Błąd przy wczytywaniu strefy czasowej"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "Bład przy wczytywaniu strefy czasowej (z %s): %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+#, fuzzy
+msgid "Changing permission of timezone: %s"
+msgstr "Zmienianie uprawnień do strefy czasowej: %s"
+
+#: ../shell/controlpanel/control.py:412
+#, fuzzy
+msgid "Error timezone does not exist."
+msgstr "Błąd, strefa czasowa nie istnieje."
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+#, fuzzy
+msgid "Could not access %s. Create standard settings."
+msgstr "Nie można odczytać %s. Stwórz standardowe ustawienia."
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Nie można określić języka dla kodu=%s."
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+#, fuzzy
+msgid "Sorry I do not speak '%s'."
+msgstr "Przykro mi, nie mówię po '%s'."
+
+#: ../shell/view/devices/network/mesh.py:105
+#, fuzzy
+msgid "Connected to a School Mesh Portal"
+msgstr "Połączono z serwerem szkolnym"
+
+#: ../shell/view/devices/network/mesh.py:107
+#, fuzzy
+msgid "Looking for a School Mesh Portal..."
+msgstr "Szukanie serwera szkolnego..."
+
+#: ../shell/view/devices/network/mesh.py:110
+#, fuzzy
+msgid "Connected to an XO Mesh Portal"
+msgstr "Połączono z portalem XO"
+
+#: ../shell/view/devices/network/mesh.py:112
+#, fuzzy
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Szukanie portalu XO..."
+
+#: ../shell/view/devices/network/mesh.py:115
+#, fuzzy
+msgid "Connected to a Simple Mesh"
+msgstr "Połączono z Simple Mesh"
+
+#: ../shell/view/devices/network/mesh.py:117
+#, fuzzy
+msgid "Starting a Simple Mesh"
+msgstr "Rozpoczynanie Simple Mesh"
+
+#: ../shell/view/devices/network/mesh.py:124
+#, fuzzy
+msgid "Unknown Mesh"
+msgstr "Nieznany Mesh"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/ps.po b/shell/po/ps.po
new file mode 100644
index 0000000..1af6cf1
--- /dev/null
+++ b/shell/po/ps.po
@@ -0,0 +1,424 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2008-01-09 11:20+0000\n"
+"Last-Translator: usman mansoor ansari <jalalkut@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "نوم:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "د رنګ بدلون لپاره ټك كړئ:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "شا"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "هوكې"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "بل"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "ملګرې لرکول"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "ملګرې جوړول"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "بلون %s ته"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "لركول"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "پرانېستل"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "ورځپاڼې ته زياتول"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "د ټوټه دړې څيزونه: %s."
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "كلي ځېل:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "د كره توب ځېل:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "د کوډه کښنه ځېل:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "پيلونه..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "کارمخینه"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "تمېدل"
+
+#: ../shell/view/Shell.py:285
+#, fuzzy
+msgid "Screenshot"
+msgstr "پرده انځور"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "بیاپیلون"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "ګلول-بندول"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "نومکښل"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "ناپيوستل"
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "مېش جال"
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "يوځايېنه"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "زما د بېټرۍ ژوند"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "بېټرۍ چارجېږي"
+
+#: ../shell/view/devices/battery.py:96
+#, fuzzy
+msgid "Battery discharging"
+msgstr "بېټري نه چارجېږي"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "بېټري بشپړه چارج شوه"
+
+#: ../shell/view/devices/network/wireless.py:61
+#, fuzzy
+msgid "Disconnected"
+msgstr "ناپيوستل"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "چېنل"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "ګاونډېتوب"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "ډله"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "کور"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "چارندتیا"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "ونډول له:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "ځاني"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "زما ګاونډيتوب"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "خوندي كول"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "ناکړ"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "بیاکړ"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "لمېسل"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "سرېښل"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s چارندتیا"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "تېروتنې ساتل"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "تېروتنې ساتل: ټول بدلونونه به له لاسه وركړئ"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "مه تمېږه"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr "پ هره توګه تمېدل"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "رنګول"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "هو"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "ادامه وركول"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "هو"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d كال"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d كلونه"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d مياشت"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d مياشتې"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d اونۍ"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d اونۍ"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d ورځ"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d ورځې"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d ساعت"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d ساعتونه"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d دقيقه"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d دقيقې"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d ثانيه"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d ثانيې"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr "_او_"
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr "،_"
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "د بدلونونو كارولو لپاره تاسې بايد شوګر بیاپیل كړئ.\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "د بدلوونې رنګ په ټاكنه كۍ تېروتنه."
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "په مالومو رنګونو كې تېروتنې بدلوونې"
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "بندول"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "روښانول"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "ايالت ناڅرګند دى."
+
+#: ../shell/controlpanel/control.py:332
+#, fuzzy
+msgid "Error in specified radio argument use on/off."
+msgstr "په ټاكلي راډيو كې تېروتنې "
+
+#: ../shell/controlpanel/control.py:336
+#, fuzzy
+msgid "Permission denied. You need to be root to run this method."
+msgstr "پرېښلې رد شو. ددې لېلې چلولو لپاره بايد تاسې ريښه اوسـئ"
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "د مهالزون په لوستتنه كې تېروتنې"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "تېروتنه مهالزون لمېسل (له %s): %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "مهالزون پرېښلې د بدلون په حال كې: %s"
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr "تېروتنه، مهالزون شتون نلري."
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "%s ته لاسرسې نه كېږي. كره امستنې وپنځوئ"
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "د code=%s لپاره ژبه مالومه نكړاى شوه."
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "بښنه غواړم زه خبرې نه كوم '%s'."
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "د ښوونځي مېش ور سره پيوست شو."
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "د ښوونځي مېش ور لپاره لټون"
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "د XO مېش ور سره پيوست شو."
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "د XO مېش ور لپاره لټون"
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "له ساده مېش سره پيوست شو."
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "د ساده مېش پيلېدنه"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "ناڅرګنده مېش"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/pseudo.po b/shell/po/pseudo.po
new file mode 100644
index 0000000..e184567
--- /dev/null
+++ b/shell/po/pseudo.po
@@ -0,0 +1,517 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:147
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:40
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr ""
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
diff --git a/shell/po/pt.po b/shell/po/pt.po
new file mode 100644
index 0000000..f2814fb
--- /dev/null
+++ b/shell/po/pt.po
@@ -0,0 +1,1481 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-09-05 00:31-0400\n"
+"PO-Revision-Date: 2009-09-24 19:08-0400\n"
+"Last-Translator: Eduardo H. Silva <HoboPrimate@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: pt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 1.2.1\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Sobre mim"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Precisas de introduzir um nome."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "traço: cor=%s tonalidade=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "traço: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "preenchimento: cor=%s tonalidade=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "preenchimento: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Erro nos modificadores de cor especificados."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Erro nas cores especificadas."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "Nome:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Clica para mudar a tua cor:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Sobre o meu Computador"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Não disponível"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Identidade"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Número de Série:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Software"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Versão do software:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "Firmware da rede sem fios"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Copyright e Licença"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"O Sugar é a interface gráfica de utilizador que estás a utilizar. O Sugar é "
+"software livre, licenciado sob a GNU General Public License, e és bem vindo "
+"a fazer alterações a ele e/ou a distribuir cópias dele, segundo certas "
+"condições descritas a seguir."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Licença Completa:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Data & Hora"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Erro: fuso horário não existe."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr "Fuso horário"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Moldura"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "O valor tem que ser um número inteiro."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "nunca"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "instantâneo"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s segundos"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Atraso na Activação"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Canto"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Lado"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "Teclado"
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr "Modelo de teclado"
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr "Tecla(s) para alterar disposição"
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr "Disposições de teclado"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Linguagem"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Não foi possível aceder a ~/.i18n. Cria definições normais."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Não foi possível determinar a linguagem para o código=%s."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Desculpa, eu não falo '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"Adiciona linguagens na ordem que preferires. Se uma tradução não estiver "
+"disponível, será usada a próxima na lista."
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Rede"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "O estado é desconhecido."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Erro no argumento de rádio especificado, utiliza on/off."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Erro no argumento especificado, utiliza 0/1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Rede sem fios"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Desliga o rádio da rede sem fios para poupar na carga da bateria"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Rádio:"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "Descarta o histórico da rede se tiveres problemas em ligares-te à rede"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Descartar histórico da rede"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Colaboração"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"O servidor é o equivalente a em que qual quarto estás tu; pessoas no mesmo "
+"servidor poderão ver-se umas às outras, mesmo que não estejam na mesma rede."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Servidor:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Energia"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Erro no argumento de gestão de energia automática, utiliza on/off."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Erro no argumento de gestão de energia extrema, utiliza on/off."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Gestão de energia"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Gestão automática de energia (aumenta o tempo de bateria)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Gestão extrema de energia (desliga o rádio da rede sem fios, aumenta o tempo "
+"de bateria)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Actualização do software"
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"Actualizações do software corrigem erros, eliminam vulnerabilidades de "
+"segurança, e fornecem novas funcionalidades."
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr "A verificar %s..."
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr "A transferir %s..."
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr "A actualizar %s..."
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr "O teu software está actualizado"
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "Podes instalar %s actualização"
+msgstr[1] "Podes instalar %s actualizações"
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr "A verificar actualizações..."
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr "A instalar actualizações..."
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s actualização foi instalada"
+msgstr[1] "%s actualizações foram instaladas"
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr "Instalação selecionada"
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr "Tamanho da transferência: %s"
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "Da versão %(current)d para a versão %(new)s (Tamanho: %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+msgid "None"
+msgstr "Nenhum"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr "1 KB"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f KB"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "A minha bateria"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Removida"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "A recarregar"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Resta muito pouca energia"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d restantes"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Recarregada"
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr "Endereço IP: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr "Desligar..."
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr "Criar uma nova rede sem fios"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:264
+msgid "Connecting..."
+msgstr "A Ligar..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:270
+msgid "Connected"
+msgstr "Ligado"
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr "Canal"
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr "Rede com fios"
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr "Velocidade"
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr "Rede %s do %s"
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Os meus altifalantes"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Retirar do silêncio"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Silenciar"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr "Mesh"
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Grupo"
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Casa"
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Actividade"
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr "Imagem do ecrã"
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "Imagem do ecrã de \"%s\""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr "URL da cópia de segurança"
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"A cor do ícone XO que é utilizada em todo o ambiente gráfico. O texto é "
+"composto pela cor de traço e a de preenchimento, e o formato é o das cores "
+"rgb. Por exemplo: #AC32FF, #9A5200"
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr "Atraso nos cantos"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr "Atraso na activação da moldura utilizando os cantos."
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Atraso na activação da moldura utilizando os lados."
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr "Atraso nos lados"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr "Posicionamento dos favoritos"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr "Modo de continuação dos favoritos"
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"Se TRUE (verdadeiro), o Sugar irá tornar-nos pesquisáveis pelos outros "
+"utilizadores do servidor Jabber."
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+"Se TRUE (verdadeiro), o Sugar irá mostrar uma opção de \"Terminar a sessão\"."
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr "Servidor Jabber"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr "Disposições de teclado"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr "Modelos de teclado"
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr "Opções de teclado"
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr "Posicionamento da vista de favoritos"
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+"Lista de disposições de teclado. Cada entrada deve estar no formato "
+"disposição(variante)"
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr "Lista de opções do teclado."
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr "Energia automática"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr "Energia automática."
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr "Energia extrema"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr "Energia Extrema."
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr "Publicar ao Gadget"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr "Definição para silenciar o dispositivo de som"
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr "Mostrar terminar a sessão"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr "Som silenciado"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr "O modelo de teclado a ser utilizado"
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr "Definição do fuso horário para o sistema."
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr "O Url do servidor jabber a utilizar."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr "O Url onde a cópia de segurança é guardada"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr "Cor do utilizador"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr "Nome do utilizador"
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr "Nome do utilizador que é utilizado em todo o ambiente gráfico."
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr "Volume do som"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr "Volume de som para o dispositivo de som."
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"Quando está no modo de continuação, clicar num ícone favorito irá fazer com "
+"que seja continuada a última entrada dessa actividade."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: AVISO, foram encontradas mais que uma opção com o mesmo "
+"nome: módulo %s: %r "
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s não é uma opção disponível"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Utilização: sugar-control-panel [ opção] key [ args ...] \n"
+" Controle do ambiente sugar. \n"
+" Opções: \n"
+" -h mostrar esta mensagem de ajuda e sair \n"
+" -l listar todas as opções disponíveis \n"
+" -h key mostrar informação sobre esta chave \n"
+" -g key obter o valor actual desta chave \n"
+" -s key colocar o valor actual desta chave \n"
+" -c key eliminar o valor actual desta chave \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Para aplicar as alterações tens que reiniciar o açúcar (sugar).\n"
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr "Aviso"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "As alterações feitas necessitam que reinicies"
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr "Cancelar alterações"
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Mais tarde"
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr "Reiniciar agora"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "Finalizar"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr "Título"
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr "Versão"
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr "Data"
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr "Versão %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr "Confirma apagar"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Confirma apagar: Queres apagar permanentemente %s?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Guardar"
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:407
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr "Apagar"
+
+#: ../src/jarabe/desktop/activitieslist.py:428
+msgid "Remove favorite"
+msgstr "Remover favorito"
+
+#: ../src/jarabe/desktop/activitieslist.py:432
+msgid "Make favorite"
+msgstr "Tornar favorito"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Disposição livre"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Anel"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Espiral"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Caixa"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Triângulo "
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr "O Registo Falhou"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr "O Registo teve sucesso"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr "Estás agora registado com o teu servidor de escola."
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr "Registar"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Actualização do software"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"Actualiza as tuas actividades para assegurar a compatibilidade com o teu "
+"novo software"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Verificar agora"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Vista de lista"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Vista de favoritos"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr "Tipo de chave:"
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr "Tipo de Autenticação:"
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr "WPA e WPA2 pessoal"
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr "Segurança da rede sem fios:"
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr "Ligar"
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr "Desligar"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:466
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr "Continuar"
+
+#: ../src/jarabe/desktop/meshbox.py:471
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr "Juntar-se"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "Não foi possível ligar ao servidor."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "Não foi possível ao servidor completar o pedido."
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr "Recusar"
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr "%s de %s"
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr "Transferência de %r"
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr "Aceitar"
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+#, fuzzy
+msgid "Dismiss"
+msgstr "Descartar"
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr "Transferir para %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:52 ../src/jarabe/view/palettes.py:218
+msgid "Remove"
+msgstr "Remover"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "Abrir"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "Abrir com"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "Recorte de %s"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Vizinhança"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "Clica para mudar a cor:"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Voltar"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "Próximo"
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "Sem título"
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr "Sem pré-visualização"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr "Tipo: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr "Desconhecido"
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr "Data: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr "Tamanho: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr "Sem data"
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr "Participantes:"
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr "Descrição:"
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr "Etiquetas:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Diário"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Procurar"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "Qualquer altura"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Hoje"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Desde ontem"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Esta semana"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Este mês"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Este ano"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Qualquer pessoa"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Os meus amigos"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "A minha turma"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Qualquer coisa"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "Copiar"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr "Iniciar"
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr "O teu Diário está vazio"
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr "Nenhuma entrada encontrada"
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr "Limpar a busca"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "O teu Diário está cheio"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"Por favor apaga algumas entradas antigas do teu diário para libertar espaço "
+"para novas."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Mostrar o diário"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Escolhe um objecto"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Fechar"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr "Continuar com"
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr "Iniciar com"
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr "Enviar para"
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr "Ver detalhes"
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr "Não está presente nenhum amigo"
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr "Não foi encontrada uma ligação válida"
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr "Não existe nenhuma actividade para continuar a entrada"
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr "Não existe nenhuma actividade para iniciar a entrada"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Remover amigo"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Fazer amigo"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Desligar"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Terminar a sessão"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "As minhas definições"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Convidar para %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "A Iniciar..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr "Ver código-fonte"
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr "Parar"
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr "Iniciar novo"
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr "Mostrar os conteúdos"
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB Livres"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Código-fonte da instância"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Código-fonte"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "Código-fonte do pacote de actividade"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "Ver o código-fonte: %r"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "Não foi possível obter os dados necessários para o registo."
+
+#~ msgid "Unmount"
+#~ msgstr "Remover"
+
+#~ msgid "Restart"
+#~ msgstr "Reiniciar"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; e Contribuidores."
+
+#~ msgid "Document"
+#~ msgstr "Documento"
+
+#~ msgid "Resume by default"
+#~ msgstr "Continuar por omissão"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Tipo de Encriptação:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid "Disconnecting..."
+#~ msgstr "A Desligar..."
+
+#~ msgid "Mesh Network"
+#~ msgstr "Rede Mesh"
+
+#~ msgid "Disconnected"
+#~ msgstr "Desligado"
+
+#~ msgid "About my XO"
+#~ msgstr "Sobre o meu XO"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Ligado a um Portal Mesh de Escola"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "À procura de um Portal Mesh de Escola..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Ligado a um Portal Mesh de XO"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "À procura de um Portal Mesh de XO..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Ligado a uma Mesh Simples"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "A iniciar uma Mesh Simples"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Mesh Desconhecida"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Objecto da Área de Transferência: %s"
+
+#~ msgid "You must enter a server."
+#~ msgstr "Precisas de introduzir um servidor."
+
+#~ msgid "Control Panel"
+#~ msgstr "Painel de Controlo"
+
+#~ msgid "© 2008 One Laptop per Child Assocation "
+#~ msgstr "© 2008 One Laptop per Child Association"
+
+#~ msgid "Sugar is the graphical user interface that "
+#~ msgstr "Sugar é a interface gráfica que estás a utilizar."
+
+#~ msgid "off"
+#~ msgstr "desligar"
+
+#~ msgid "on"
+#~ msgstr "ligar"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "Permissão negada. Tens que ser administrador para correr este método."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "Erro ao ler a zona horária"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Erro ao copiar a zona horária (de %s): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Modificando permissão da zona horária: %s"
+
+#~ msgid "Add to journal"
+#~ msgstr "Adicionar ao Diário"
+
+#~ msgid "Reboot"
+#~ msgstr "Reiniciar"
+
+#~ msgid "My Battery life"
+#~ msgstr "Energia da bateria"
+
+#~ msgid "Battery charging"
+#~ msgstr "Bateria a carregar"
+
+#~ msgid "Battery discharging"
+#~ msgstr "Bateria a descarregar"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Bateria totalmente carregada"
+
+#~ msgid "Share with:"
+#~ msgstr "Partilhar com:"
+
+#~ msgid "Private"
+#~ msgstr "Privado"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "Minha Vizinhança"
+
+#~ msgid "Undo"
+#~ msgstr "Desfazer"
+
+#~ msgid "Redo"
+#~ msgstr "Refazer"
+
+#~ msgid "Paste"
+#~ msgstr "Colar"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s Actividade"
+
+#~ msgid "Keep error"
+#~ msgstr "Guardar erro"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "Guardar erro: todas as mudanças serão perdidas"
+
+#~ msgid "Don't stop"
+#~ msgstr "Não pares"
+
+#~ msgid "Stop anyway"
+#~ msgstr "Parar à mesma"
+
+#~ msgid "Continue"
+#~ msgstr "Continuar"
+
+#~ msgid "OK"
+#~ msgstr "OK"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d ano"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d anos"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d mês"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d meses"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d semana"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d semanas"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d dia"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d dias"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d hora"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d horas"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d minuto"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d minutos"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d segundo"
+
+#~ msgid " and "
+#~ msgstr " e "
+
+#~ msgid ", "
+#~ msgstr ", "
diff --git a/shell/po/pt_BR.po b/shell/po/pt_BR.po
new file mode 100644
index 0000000..6e5eb3e
--- /dev/null
+++ b/shell/po/pt_BR.po
@@ -0,0 +1,438 @@
+# translation of olpc-sugar-pt_BR.po to Brazilian Portuguese
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Diego Búrigo Zacarão <diegobz@gmail.com>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: olpc-sugar-pt_BR\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-12-11 21:39+0530\n"
+"PO-Revision-Date: 2008-01-27 18:23-0500\n"
+"Last-Translator: Eduardo H. Silva <HoboPrimate@gmail.com>\n"
+"Language-Team: Brazilian Portuguese <fedora-docs-br@redhat.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "Nome:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "Clique para mudar a cor:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Voltar"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "Pronto"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "Próximo"
+
+#: ../shell/view/BuddyMenu.py:84
+msgid "Remove friend"
+msgstr "Remover amigo"
+
+#: ../shell/view/BuddyMenu.py:87
+msgid "Make friend"
+msgstr "Fazer amigo"
+
+#. FIXME check that the buddy is not in the activity already
+#: ../shell/view/BuddyMenu.py:96
+msgid "Invite"
+msgstr "Convidar"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "Remover"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "Abrir"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "Adicionar ao diário"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Objeto da prancheta: %s"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "Vizinhança"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "Grupo"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "Casa"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "Atividade"
+
+#: ../services/clipboard/objecttypeservice.py:32
+msgid "Text"
+msgstr "Texto"
+
+#: ../services/clipboard/objecttypeservice.py:36
+msgid "Image"
+msgstr "Imagem"
+
+#: ../shell/view/Shell.py:276
+msgid "Screenshot"
+msgstr "Foto da tela"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "Desligar"
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "Rede Mesh"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "Carga de minha Bateria"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "Carregando a bateria"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "Descarregando a bateria"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "Bateria completamente carregada"
+
+#: ../lib/sugar/activity/activity.py:122
+msgid "Keep"
+msgstr "Manter"
+
+#: ../sugar/activity/activity.py:74
+msgid "Share"
+msgstr "Compartilhar"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:128
+msgid "Stop"
+msgstr "Parar"
+
+#: ../lib/sugar/activity/activity.py:450
+#, python-format
+msgid "%s Activity"
+msgstr "Atividade %s"
+
+#: ../shell/view/BuddyMenu.py:109
+#, python-format
+msgid "Invite to %s"
+msgstr "Convidar para %s"
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "Tipo de chave:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "Tipo de Autenticação:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "Tipo de Encriptação:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "Iniciando..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "Continuar"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "Reiniciar"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "Cadastrar"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "Desconectar"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "Desconectado"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "Canal"
+
+#: ../lib/sugar/activity/activity.py:111
+msgid "Share with:"
+msgstr "Partilhar com:"
+
+#: ../lib/sugar/activity/activity.py:113
+msgid "Private"
+msgstr "Privado"
+
+#: ../lib/sugar/activity/activity.py:114
+msgid "My Neighborhood"
+msgstr "Minha Vizinhança"
+
+#: ../lib/sugar/activity/activity.py:241
+msgid "Undo"
+msgstr "Desfazer"
+
+# optei pela forma de "fazer de novo" ao invés de refazer por acreditar que ela seja mais fácil de compreender para crianças.
+#: ../lib/sugar/activity/activity.py:246
+msgid "Redo"
+msgstr "Fazer de novo"
+
+#: ../lib/sugar/activity/activity.py:256
+msgid "Copy"
+msgstr "Copiar"
+
+#: ../lib/sugar/activity/activity.py:261
+msgid "Paste"
+msgstr "Colar"
+
+#: ../lib/sugar/activity/activity.py:820
+msgid "Keep error"
+msgstr "Erro ao manter"
+
+#: ../lib/sugar/activity/activity.py:821
+msgid "Keep error: all changes will be lost"
+msgstr "Erro ao manter: todas as alterações serão desfeitas"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Don't stop"
+msgstr "Não pare"
+
+#: ../lib/sugar/activity/activity.py:827
+msgid "Stop anyway"
+msgstr "Pare mesmo assim"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "Ok"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "Continuar"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "OK"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d ano"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d anos"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d mês"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d meses"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d semana"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d semanas"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d dia"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d dias"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d hora"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d horas"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d minuto"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d minutos"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d segundo"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d segundos"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr " e "
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ", "
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Para terminar suas mudanças você deve reiniciar o sugar.\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "Erro nos alteradores de cor selecionados."
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "Erro nas cores especificadas."
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "desligado"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "ligado"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "Estado desconhecido"
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr "Erro no argumento de rádio especificado, use on/off."
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+"Permissão negada. Você precisa ser o usuário root para executar esse método."
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "Erro ao ler o fuso horário"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "Erro ao copiar o fuso horário (de %s): %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "Mudando a permissão do fuso horário: %s"
+
+#: ../shell/controlpanel/control.py:413
+msgid "Error timezone does not exist."
+msgstr "Erro: fuso horário não existe."
+
+#: ../shell/controlpanel/control.py:418 ../shell/controlpanel/control.py:438
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "Não foi possível acessar %s. Crie configurações padrão."
+
+#: ../shell/controlpanel/control.py:466
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Não foi possível determinar a língua para o código=%s."
+
+#: ../shell/controlpanel/control.py:476
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Desculpe, eu não falo '%s'."
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "Conectado ao Portal Mesh da Escola"
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "Procurando por um Portal Mesh da Escola..."
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "Conectado ao Portal Mesh de um XO"
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Procurando pelo Portal Mesh de algum XO..."
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "Conectado a uma Mesh Simples"
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "Iniciando uma Mesh Simples"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "Mesh desconhecida"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr "Sobre este XO"
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr "Não disponível"
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "Juntar-se"
diff --git a/shell/po/qu.po b/shell/po/qu.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/qu.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/ro.po b/shell/po/ro.po
new file mode 100644
index 0000000..69b541f
--- /dev/null
+++ b/shell/po/ro.po
@@ -0,0 +1,419 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2008-01-07 18:20+0000\n"
+"Last-Translator: David Lazar <david@davidlazar.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "Nume:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Înapoi"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "Gata"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "Următor"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "Şterge prieten"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "Adaugă prieten"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "Deschide"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "Adaugă la jurnal"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "Reia"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "Oprește"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "Reporneşte"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "Înregistrează"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "Durata bateriei mele"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "Bateria se încarcă"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "Bateria se descarcă"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "Acasă"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "Activitate"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "Păstrează"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "Anulează"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "Refă"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "Copiază"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "Lipeşte"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "Anulează"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "Ok"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "Continuă"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "OK"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d an"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d ani"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d lună"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d luni"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d săptămână"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d săptămâni"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d zi"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d zile"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d oră"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d ore"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d minut"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d minute"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d secundă"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d secunde"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr " şi "
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ", "
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/ru.po b/shell/po/ru.po
new file mode 100644
index 0000000..b49f59a
--- /dev/null
+++ b/shell/po/ru.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2007-12-23 09:35+0000\n"
+"Last-Translator: Maxim Osipov <maxim.osipov@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "Имя:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "Кликните для изменения цвета:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Назад"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "Готово"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "Далее"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "Убрать друга"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "Создать друга"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "Пригласить в %s"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "Удалить"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "Открыть"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "Добавить в журнал"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "Объект буфера: %s."
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "Тип ключа:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "Тип аутентификации:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "Тип шифрования:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "Запуск..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "Продолжить"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "Стоп"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "Снимок экрана"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "Перезагрузить"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "Выключить"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "Зарегистрироваться"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "Разъединить..."
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "Местная Сеть"
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "Присоединиться"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "Моя Батарейка"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "Батарейка заряжается"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "Батарейка разряжается"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "Батарейка полностью заряжена"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "Не подключен"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "Канал"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "Соседи"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "Группа"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "Дом"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "Активность"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "Разделить с:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "Личное"
+
+# в русском языке мы не Пишем Каждое Слово с Заглавной Буквы
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "Мои соседи"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "Хранить"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "Отменить"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "Повторить"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "Копировать"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "Вставить"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s Активность"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "Ошибка сохранения"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "Ошибка сохранения: все изменения будут потеряны"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "Не останавливаться"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr "Все равно остановиться"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "Отмена"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "Ок"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "Продолжить"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "ОК"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d год"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d лет"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d месяц"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d месяцев"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d неделя"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d недель"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d день"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d дней"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d час"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d часов"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d минута"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d минут"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d секунда"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d секунд"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr " и "
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ", "
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Чтобы применить изменения перезапустите sugar.\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "Ошибка в определении цветов."
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "Ошибка выбора цветов."
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "выкл"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "вкл"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "Состояние неизвестно."
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr "Ошибка выбора, используйте вкл/выкл."
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr "Доступ запрещен. Вы должны быть root-ом чтобы выполнить этот метод."
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "Ошибка чтения часового пояса."
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "Ошибка копирования часового пояса (из %s): %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "Изменяются права доступа часового пояса: %s"
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr "Ошибка - часовой пояс не существует."
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "Нет доступа к %s. Создайте стандартные настройки."
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Язык с кодом=%s не определен."
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Я не говорю по '%s'."
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "Подключен к Местному Школьному Серверу"
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "Поиск Местного Школьного Сервера..."
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "Подключен к Местному Серверу XO"
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Поиск Местного Сервера XO..."
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "Подключен к Простой Местной Сети"
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "Запуск Простой Местной Сети"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "Неизвестная Местная Сеть"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/rw.po b/shell/po/rw.po
new file mode 100644
index 0000000..c1809ae
--- /dev/null
+++ b/shell/po/rw.po
@@ -0,0 +1,596 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-07-23 07:44-0400\n"
+"PO-Revision-Date: 2008-08-06 03:51-0400\n"
+"Last-Translator: Carine Umutesi <carine.umutesi@rita.rw>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65
+#: ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "Izina"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "kanda uhindure ibara"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr " Inyuma"
+
+#: ../src/intro/intro.py:159
+#: ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "Icyakozwe"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "Ibikurikira"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "Gira inshuti"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "Gira inshuti"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "Tumira ku %s"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "Kuraho"
+
+#: ../src/view/clipboardmenu.py:53
+#: ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "Fungura"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+#: ../src/view/home/HomeBox.py:86
+msgid "Keep"
+msgstr "Gumana"
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr "Fungura ukoresheje"
+
+#: ../src/view/clipboardmenu.py:216
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "object y`ikibaho: %s."
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "Ubwoko bw'Urufunguzo:"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "Ubwoko bwo Kwivuga:"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "Encryption Type:"
+
+#: ../src/view/Shell.py:240
+msgid "Screenshot"
+msgstr "Ekara ntoya"
+
+#: ../src/view/home/HomeBox.py:80
+msgid "Confirm erase"
+msgstr "Emeza gusiba"
+
+#: ../src/view/home/HomeBox.py:82
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Emeza gusiba: urashaka gusiba burundu %s?"
+
+#: ../src/view/home/HomeBox.py:89
+#: ../src/view/palettes.py:120
+msgid "Erase"
+msgstr "Gusiba"
+
+#: ../src/view/home/HomeBox.py:215
+msgid "List view"
+msgstr "Ibigaragara ku rutonde"
+
+#: ../src/view/home/HomeBox.py:216
+#, fuzzy
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/view/home/HomeBox.py:273
+msgid "Favorites view"
+msgstr "Reba ibyagushimishije"
+
+#: ../src/view/home/HomeBox.py:274
+#, fuzzy
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:282
+msgid "Freeform"
+msgstr "Freeform"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:289
+msgid "Ring"
+msgstr "Isone"
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "Huza"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "Tandukanya"
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "Gutandukanya"
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr "Guhuza"
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr "Byahujwe"
+
+#: ../src/view/home/MeshBox.py:211
+#: ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr "urusobe rwa rezo"
+
+#: ../src/view/home/MeshBox.py:214
+#: ../src/view/devices/network/wireless.py:119
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr "Byatandukanijwe"
+
+#: ../src/view/home/MeshBox.py:302
+#: ../src/view/palettes.py:61
+msgid "Resume"
+msgstr "Komeza"
+
+#: ../src/view/home/MeshBox.py:307
+#: ../src/view/frame/activitiestray.py:205
+msgid "Join"
+msgstr "Huza"
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr "Batiri yanjye"
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr "Gusharija "
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr "Hasiagaye ingufu nke cyane"
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d isigaye"
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr "irasharije"
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr "Imizindaro Yanjye"
+
+#: ../src/view/devices/speaker.py:119
+msgid "Unmute"
+msgstr "Unmute"
+
+#: ../src/view/devices/speaker.py:122
+msgid "Mute"
+msgstr "Mute"
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr "Byatandukanijwe"
+
+#: ../src/view/devices/network/wireless.py:137
+msgid "Channel"
+msgstr "Umuyoboro"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "Ubuturanyi"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "Itsinda"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "Murugo"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "Igikorwa"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid "sugar-control-panel: WARNING, found more than one option with the same name: %s module: %r"
+msgstr "sugar-control-panel: WARNING, found more than one option with the same name: %s module: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s not an available option"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "To apply your changes you have to restart sugar.\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "Kuraho"
+
+#: ../src/controlpanel/toolbar.py:121
+#: ../src/view/home/favoritesview.py:294
+msgid "Ok"
+msgstr "Nibyo"
+
+#: ../src/controlpanel/sectionview.py:34
+#: ../src/controlpanel/gui.py:260
+msgid "Changes require restart"
+msgstr "impinduka zikenera gusubirwamo"
+
+#: ../src/controlpanel/gui.py:259
+msgid "Warning"
+msgstr "Kwisubiraho"
+
+#: ../src/controlpanel/gui.py:263
+msgid "Cancel changes"
+msgstr "kureka impinduka"
+
+#: ../src/controlpanel/gui.py:267
+msgid "Later"
+msgstr "nyumaho gato"
+
+#: ../src/controlpanel/gui.py:271
+msgid "Restart now"
+msgstr "kongera gutangira ubungubu"
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr "ugomba kwinjiza izina"
+
+#: ../src/controlpanel/model/aboutme.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "stroke: ibara=%s hue=%s"
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr "stroke: %s"
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "fill: color=%s hue=%s"
+
+#: ../src/controlpanel/model/aboutme.py:76
+#, python-format
+msgid "fill: %s"
+msgstr "fill: %s"
+
+#: ../src/controlpanel/model/aboutme.py:87
+msgid "Error in specified color modifiers."
+msgstr "Ikosa muri specified ibara modifiers."
+
+#: ../src/controlpanel/model/aboutme.py:90
+msgid "Error in specified colors."
+msgstr "Ikosa mu mabara yatoranijwe"
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "ntago byabashije kuboneka"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr "Ikosa timezonentiribaho."
+
+#: ../src/controlpanel/model/frame.py:38
+#: ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr "umubare ugomba kuba udafite undi mubare inyuma yakitso"
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Could not access ~/.i18n. Create standard settings."
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Ururimi rwa code=%s could not be determined."
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "ihangane sinshoboye kuvuga '%s'"
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr "You must enter a server."
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr "States ntizizwi"
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr "Ikosain specified radio argument use on/off."
+
+#: ../src/controlpanel/model/power.py:57
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Ikosa muri automatic pm argument,koresha on/off."
+
+#: ../src/controlpanel/model/power.py:86
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Ikosa muri extreme pm argument, use on/of."
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr "Ibinyerecyeyeho"
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr "kanda kugirango uhindure irange"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr "About my XO"
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr "Erekana"
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr "Serial Number:"
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr "porogurame"
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr "Kubaka"
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr "Itariki n`igihe"
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr "Timezone"
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr "Frame"
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr "ntibizongere"
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr "instantaneous"
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr "%s seconds"
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr "Activation Delay"
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr "Inguni"
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr "Inshonda"
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr "Ururimi"
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr "Rezo"
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr "Rezo itagira intsinga"
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr "Isakaza majwi"
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr "Urusobekerane"
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr "Server:"
+
+#: ../src/controlpanel/view/power.py:27
+msgid "Power"
+msgstr "Ingufu"
+
+#: ../src/controlpanel/view/power.py:51
+msgid "Power management"
+msgstr "Ubugenzuzi bw`ingufu"
+
+#: ../src/controlpanel/view/power.py:61
+msgid "Automatic power management (increases battery life)"
+msgstr "Ubugenzuzi bw`ingufu buri otomatike (ongera ubuzima bwa batiri)"
+
+#: ../src/controlpanel/view/power.py:89
+msgid "Extreme power management (disables wireless radio, increases battery life)"
+msgstr "Extreme power management (disables wireless radio, increases battery life)"
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr "Connected to a School Mesh Portal"
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr "Looking for a School Mesh Portal..."
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr "Connected to an XO Mesh Portal"
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr "Looking for an XO Mesh Portal..."
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr "Connected to a Simple Mesh"
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr "Starting a Simple Mesh"
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr "isobekerane ritazwi"
+
+#: ../src/view/frame/activitiestray.py:210
+msgid "Decline"
+msgstr "kugabanyuka kwikintu"
+
+#: ../src/view/home/favoritesview.py:285
+msgid "Registration Failed"
+msgstr "Kwiyandikisha birananiranye"
+
+#: ../src/view/home/favoritesview.py:286
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/view/home/favoritesview.py:288
+msgid "Registration Successful"
+msgstr "Kwiyandikisha byatunganye"
+
+#: ../src/view/home/favoritesview.py:289
+msgid "You are now registered with your school server."
+msgstr "Ubu wanditswe muri server y`ishuri"
+
+#: ../src/view/home/favoritesview.py:405
+msgid "Control Panel"
+msgstr "Control Panel"
+
+#: ../src/view/home/favoritesview.py:416
+msgid "Restart"
+msgstr "kongera gutangira"
+
+#: ../src/view/home/favoritesview.py:421
+msgid "Shutdown"
+msgstr "kuzimya"
+
+#: ../src/view/home/favoritesview.py:427
+msgid "Register"
+msgstr "kwiyandikisha"
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr "Gutangira..."
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr "Hagarara"
+
+#: ../src/view/palettes.py:104
+msgid "Start"
+msgstr "Tangira"
+
+#: ../src/view/palettes.py:132
+msgid "Remove favorite"
+msgstr "Kuraho icyo ukunda"
+
+#: ../src/view/palettes.py:136
+msgid "Make favorite"
+msgstr "Kora icyo ukunda"
+
+#: ../src/view/palettes.py:185
+msgid "Show contents"
+msgstr "Erekana ibigize"
+
+#: ../src/view/palettes.py:209
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB Free"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
diff --git a/shell/po/sd.po b/shell/po/sd.po
new file mode 100644
index 0000000..e184567
--- /dev/null
+++ b/shell/po/sd.po
@@ -0,0 +1,517 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:147
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:40
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr ""
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
diff --git a/shell/po/si.po b/shell/po/si.po
new file mode 100644
index 0000000..c86330e
--- /dev/null
+++ b/shell/po/si.po
@@ -0,0 +1,899 @@
+# translation of sugar.po to Sinhala
+# Rashan Anushka <rashan.uoc@gmail.com>, 2008.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+msgid ""
+msgstr ""
+"Project-Id-Version: sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-25 00:30-0400\n"
+"PO-Revision-Date: 2008-09-30 07:45-0400\n"
+"Last-Translator: Rashan Anushka <rashan.uoc@gmail.com>\n"
+"Language-Team: Sinhala <si@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/window.py:93 ../src/controlpanel/aboutme/view.py:100
+msgid "Name:"
+msgstr "නම:"
+
+#: ../src/intro/window.py:125
+msgid "Click to change color:"
+msgstr "පාට වෙනස් කිරීමට ක්ලික් කරන්න:"
+
+#: ../src/intro/window.py:175 ../src/journal/detailview.py:119
+msgid "Back"
+msgstr "ආපසු"
+
+#: ../src/intro/window.py:189 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "කළා"
+
+#: ../src/intro/window.py:192
+msgid "Next"
+msgstr "ඊළඟ"
+
+#: ../src/view/BuddyMenu.py:60
+msgid "Remove friend"
+msgstr "මිතුරා ඉවත් කරන්න"
+
+#: ../src/view/BuddyMenu.py:63
+msgid "Make friend"
+msgstr "මිතුරු වන්න"
+
+#: ../src/view/BuddyMenu.py:92
+#, python-format
+msgid "Invite to %s"
+msgstr "%s ට අඬගහන්න"
+
+#: ../src/view/clipboardmenu.py:51
+msgid "Remove"
+msgstr "ඉවත් කරන්න"
+
+#: ../src/view/clipboardmenu.py:56 ../src/view/clipboardmenu.py:78
+msgid "Open"
+msgstr "විවෘත කරන්න"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:61 ../src/view/home/HomeBox.py:84
+msgid "Keep"
+msgstr "තබාගන්න"
+
+#: ../src/view/clipboardmenu.py:83
+msgid "Open with"
+msgstr "විවෘත කළ යුත්තේ"
+
+#: ../src/view/clipboardmenu.py:228
+#, python-format
+msgid "%s clipping"
+msgstr "කප්පාදුව %s"
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "යතුරු වර්ගය:"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "සත්‍යාපන වර්ගය:"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "සංකේතන වර්ගය:"
+
+#: ../src/hardware/schoolserver.py:17
+msgid "Cannot obtain data needed for registration."
+msgstr "ලියාපදිංචිය සඳහා අවශ්‍ය දත්ත ලබා ගත නොහැක."
+
+#: ../src/hardware/schoolserver.py:31
+msgid "Cannot connect to the server."
+msgstr "සේවාදායකයට සම්බන්ධ විය නොහැක."
+
+#: ../src/hardware/schoolserver.py:36
+msgid "The server could not complete the request."
+msgstr "සේවාදායකයට අයදුම සම්පූර්ණ කළ නොහැක."
+
+#: ../src/view/Shell.py:251
+msgid "Screenshot"
+msgstr "තිරසටහන"
+
+#: ../src/view/home/HomeBox.py:78
+msgid "Confirm erase"
+msgstr "මකා දැමීම ස්ථීර කරන්න"
+
+#: ../src/view/home/HomeBox.py:80
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "මකා දැමීම ස්ථීරයි: ඔබට %s සදහටම මකා දැමීමට අවශ්‍යයද?"
+
+#: ../src/view/home/HomeBox.py:87 ../src/view/palettes.py:120
+#: ../src/journal/journaltoolbox.py:335 ../src/journal/palettes.py:75
+msgid "Erase"
+msgstr "මකන්න"
+
+#: ../src/view/home/HomeBox.py:117
+msgid "Software Update"
+msgstr "මෘදුකාංග යාවත්කාල කිරීම"
+
+#: ../src/view/home/HomeBox.py:118
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "ඔබගේ නව මෘදුකාංගය සමඟ අනුකූලතාව සඳහා ඔබගේ ක්‍රියාකාරකම් යාවත්කාල කරන්න"
+
+#: ../src/view/home/HomeBox.py:122 ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "අවලංගු කරන්න"
+
+#: ../src/view/home/HomeBox.py:124 ../src/controlpanel/gui.py:273
+msgid "Later"
+msgstr "පසුව"
+
+#: ../src/view/home/HomeBox.py:127
+msgid "Check now"
+msgstr "දැන් පරික්ෂා කරන්න"
+
+#: ../src/view/home/HomeBox.py:261
+msgid "List view"
+msgstr "ලැයිස්තු දසුන"
+
+#: ../src/view/home/HomeBox.py:262
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/view/home/HomeBox.py:320
+msgid "Favorites view"
+msgstr "කැමති දසුන"
+
+#: ../src/view/home/HomeBox.py:321
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "සම්බන්ධ වෙන්න"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "විසන්ධි වන්න"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "විසන්ධිවේ..."
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:159
+msgid "Connecting..."
+msgstr "සම්බන්ධවේ..."
+
+# TODO: show the channel number
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:166
+msgid "Connected"
+msgstr "සම්බන්ධ විය"
+
+#: ../src/view/home/MeshBox.py:218 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr "දැලැස ජාලය"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:221 ../src/view/devices/network/wireless.py:125
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr "විසන්ධි කරන්න..."
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/view/home/MeshBox.py:309 ../src/view/palettes.py:61
+#: ../src/journal/journaltoolbox.py:399 ../src/journal/palettes.py:57
+msgid "Resume"
+msgstr "නැවත ආරම්භ කරන්න"
+
+#: ../src/view/home/MeshBox.py:314 ../src/view/frame/activitiestray.py:206
+msgid "Join"
+msgstr "සම්බන්ධ වෙන්න"
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr "මගේ බැටරිය"
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr "ආරෝපනය වේ"
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr "ඉතා සුළු බලයක් පවතී"
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d ඉතිරියි"
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr "ආරෝපිතයි"
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr "මගේ ස්පීකරය"
+
+#: ../src/view/devices/speaker.py:125
+msgid "Unmute"
+msgstr "නිෂ්ශබ්ධතාව නවතන්න"
+
+#: ../src/view/devices/speaker.py:128
+msgid "Mute"
+msgstr "නිශ්ශබ්ද කරන්න"
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr "විසන්ධිවී ඇත"
+
+#: ../src/view/devices/network/wireless.py:143
+msgid "Channel"
+msgstr "නාලිකාව"
+
+#: ../src/view/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "වටපිටාව"
+
+#: ../src/view/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "සමූහය"
+
+#: ../src/view/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "නිවස"
+
+#: ../src/view/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "ක්‍රියාකාරකම"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: අවවාදයයි, එකම නම (%s) සහිත විකල්ප කිහිපයක් හමු විය.: "
+"මොඩියුලය: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s පවතින විකල්පයක් නොවේ"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/controlpanel/cmd.py:35
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"භාවිතාව: sugar-control-panel [ විකල්පය ] key [ තර්ක ... ] \n"
+" ශුගර් පරිසරය සඳහා පාලනය. \n"
+" විකල්ප: \n"
+" -h මෙම උදව් පණිවිඩය පෙන්වා පිටවන්න\n"
+" -l සියළු විකල්ප ලැයිස්තුගත කරන්න\n"
+" -h key key ගැන විස්තර පෙන්වන්න \n"
+" -g key key හි පවතින අගය පෙන්වන්න \n"
+" -s key key හි අගය සිටුචම් කරන්න \n"
+" "
+
+#: ../src/controlpanel/cmd.py:48
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "ඔබගේ වෙනස්කිරීම් බලපෑම සඳහා ෂුගර් යළි ඇරඹිය යුතුය.\n"
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:305
+msgid "Ok"
+msgstr "හරි"
+
+#: ../src/controlpanel/sectionview.py:42 ../src/controlpanel/gui.py:265
+msgid "Changes require restart"
+msgstr "වෙනස්කිරීම සඳහා යළි ඇරඹුමක් අවශ්‍යවේ"
+
+#: ../src/controlpanel/gui.py:264
+msgid "Warning"
+msgstr "අවවාදයයි"
+
+#: ../src/controlpanel/gui.py:268
+msgid "Cancel changes"
+msgstr "වෙනස් කිරීම් අවලංගු කරන්න"
+
+#: ../src/controlpanel/gui.py:277
+msgid "Restart now"
+msgstr "දැන් යළි ආරම්භ කරන්න"
+
+#: ../src/controlpanel/aboutme/model.py:44
+msgid "You must enter a name."
+msgstr "ඔබ විසින් නමක් ඇතුලත් කළ යුතුය."
+
+#: ../src/controlpanel/aboutme/model.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "පහර: වර්ණය=%s පැහැය=%s"
+
+#: ../src/controlpanel/aboutme/model.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr "පහර: %s"
+
+#: ../src/controlpanel/aboutme/model.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "පිරවුම: වර්ණය=%s පැහැය=%s"
+
+#: ../src/controlpanel/aboutme/model.py:76
+#, python-format
+msgid "fill: %s"
+msgstr "පිරවුම: %s"
+
+#: ../src/controlpanel/aboutme/model.py:87
+msgid "Error in specified color modifiers."
+msgstr "සැපයූ වර්ණ විකරණකාරකයේ දෝෂයකි"
+
+#: ../src/controlpanel/aboutme/model.py:90
+msgid "Error in specified colors."
+msgstr "සැපයූ වර්ණවල දෝෂයකි"
+
+#: ../src/controlpanel/aboutme/view.py:32
+#: ../src/controlpanel/aboutme/__init__.py:22
+msgid "About Me"
+msgstr "මම ගැන"
+
+#: ../src/controlpanel/aboutme/view.py:134
+msgid "Click to change your color:"
+msgstr "ඔබගේ පාට වෙනස් කිරීමට ක්ලික් කරන්න:"
+
+#: ../src/controlpanel/aboutxo/model.py:24
+msgid "Not available"
+msgstr "නොපවතී"
+
+#: ../src/controlpanel/aboutxo/view.py:55
+msgid "Identity"
+msgstr "අනන්‍යතාව"
+
+#: ../src/controlpanel/aboutxo/view.py:64
+msgid "Serial Number:"
+msgstr "අනුක්‍රමික අංකය:"
+
+#: ../src/controlpanel/aboutxo/view.py:87
+msgid "Software"
+msgstr "මෘදුකාංගය"
+
+#: ../src/controlpanel/aboutxo/view.py:96
+msgid "Build:"
+msgstr "ගොඩ නැඟුම:"
+
+#: ../src/controlpanel/aboutxo/view.py:111
+msgid "Sugar:"
+msgstr "ශුගර්:"
+
+#: ../src/controlpanel/aboutxo/view.py:126
+msgid "Firmware:"
+msgstr "ස්ථීරාංගය:"
+
+#: ../src/controlpanel/aboutxo/view.py:148
+msgid "Copyright and License"
+msgstr "කතු හිමිකම හා වරපත"
+
+#: ../src/controlpanel/aboutxo/view.py:156
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; හා සහදායකයින්."
+
+#: ../src/controlpanel/aboutxo/view.py:163
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"ශුගර් යනු ඔබ බලා සිටින මෙම චිත්‍රක පරිශීලක අතුරුමුහුණතයි. ශුගර් GNU සාධාරණ "
+"පොදු වරපත මගින් ආවරණය වන නිදහස් මෘදුකාංගයක් වන අතර එහි සඳහන් ඇතැම් කොන්දේසි "
+"වලට යටත්ව මෙය වෙනස් කිරීමට හා/හෝ පිටපත් බෙදාහැරීමට ඔබට හැකිය."
+
+#: ../src/controlpanel/aboutxo/view.py:175
+msgid "Full license:"
+msgstr "සම්පූර්ණ වරපත:"
+
+#: ../src/controlpanel/aboutxo/__init__.py:21
+msgid "About my XO"
+msgstr "මගේ XO ගැන"
+
+#: ../src/controlpanel/datetime/model.py:89
+msgid "Error timezone does not exist."
+msgstr "දෝෂයකි වේලාකලාපය නොපවතී."
+
+#: ../src/controlpanel/datetime/view.py:68
+msgid "Timezone"
+msgstr "වේලා කලාපය"
+
+#: ../src/controlpanel/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "දිනය හා වේලාව"
+
+#: ../src/controlpanel/frame/model.py:38 ../src/controlpanel/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "අගය නිඛිලයක් විය යුතුය."
+
+#: ../src/controlpanel/frame/view.py:26
+msgid "never"
+msgstr "කිසිම දිනෙක"
+
+#: ../src/controlpanel/frame/view.py:27
+msgid "instantaneous"
+msgstr "ක්ෂණිකව"
+
+#: ../src/controlpanel/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "තත්පර %s"
+
+#: ../src/controlpanel/frame/view.py:52
+msgid "Activation Delay"
+msgstr "සක්‍රියනය ප්‍රමාදය"
+
+#: ../src/controlpanel/frame/view.py:76
+msgid "Corner"
+msgstr "මුල්ල"
+
+#: ../src/controlpanel/frame/view.py:111
+msgid "Edge"
+msgstr "අයින"
+
+#: ../src/controlpanel/frame/__init__.py:21
+msgid "Frame"
+msgstr "කවුළුව"
+
+#: ../src/controlpanel/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "~/.i18n වෙත ප්‍රවේශ විය නොහැක. සම්මත සිටුවම් සාදන්න."
+
+#: ../src/controlpanel/language/model.py:114
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "කේතය=%s වන භාෂාව නිර්ණය කළ නොහැක."
+
+#: ../src/controlpanel/language/model.py:131
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "සමාවන්න මම '%s' කථා නොකරමි."
+
+#: ../src/controlpanel/language/view.py:70
+#: ../src/controlpanel/language/__init__.py:21
+msgid "Language"
+msgstr "භාෂාව"
+
+#: ../src/controlpanel/network/model.py:62
+msgid "State is unknown."
+msgstr "තත්ත්වය නොදනී."
+
+#: ../src/controlpanel/network/model.py:82
+msgid "Error in specified radio argument use on/off."
+msgstr "සැපයූ විකල්ප විස්තාරකයේ දෝෂයකි. සක්‍රීයයි/අක්‍රීයයි භාවිතා කරන්න."
+
+#: ../src/controlpanel/network/view.py:28
+#: ../src/controlpanel/network/__init__.py:21
+msgid "Network"
+msgstr "ජාලය"
+
+#: ../src/controlpanel/network/view.py:54
+msgid "Wireless"
+msgstr "රැහැන් රහිත"
+
+#: ../src/controlpanel/network/view.py:62
+msgid "Turn of the wireless radio to save battery life"
+msgstr "බැටරි ආයු කාලය සුරැකීම සඳහා රැහැන් රහිත රේඩියෝව නිවා දමන්න"
+
+#: ../src/controlpanel/network/view.py:75
+msgid "Radio"
+msgstr "රේඩියෝව"
+
+#: ../src/controlpanel/network/view.py:91
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "ොබට ජාලයට සම්බන්ධ වීමේ ගැටළු ඇතිනම් ජාල ඉතිහාසය ඉවතලන්න"
+
+#: ../src/controlpanel/network/view.py:100
+msgid "Discard network history"
+msgstr "ජාල ඉතිහාසය ඉවතලන්න"
+
+#: ../src/controlpanel/network/view.py:113
+msgid "Mesh"
+msgstr "දැලැස"
+
+#: ../src/controlpanel/network/view.py:122
+msgid "Server:"
+msgstr "සේවාදායකය:"
+
+#: ../src/controlpanel/power/model.py:55
+msgid "Error in automatic pm argument, use on/off."
+msgstr "ස්වයංක්‍රීය pm විස්තාරකයේ දෝෂයකි, සක්‍රීයයි/අක්‍රීයයි භාවිතා කරන්න."
+
+#: ../src/controlpanel/power/model.py:84
+msgid "Error in extreme pm argument, use on/off."
+msgstr "ආන්තික pm විස්තාරකයේ දෝෂයකි, සක්‍රීයයි/අක්‍රීයයි භාවිතා කරන්න."
+
+#: ../src/controlpanel/power/view.py:47
+msgid "Power management"
+msgstr "බල කළමණාකරනය"
+
+#: ../src/controlpanel/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "ස්වයංක්‍රීය බල කළමණාකරනය (බැටරි ආයු කාලය වැඩි කරයි)"
+
+#: ../src/controlpanel/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"උපරිම බල කළමණාකරනය ( රැහැන් රහිත රේඩියෝව අක්‍රිය කරයි, බැටරි ආයු කාලය වැඩි "
+"කරයි)"
+
+#: ../src/controlpanel/power/__init__.py:21
+msgid "Power"
+msgstr "ශක්තිය"
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr "පාසල් දැලැස් බිහිදොරකට සම්බන්ධ විය"
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr "පාසල් දැලැස් බිහිදොරක් සොයයි..."
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr "XO දැලැස් බිහිදොරකට සම්බන්ධ විය"
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr "XO දැලැස් බිහිදොරක් සොයයි..."
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr "සරල දැලැස් බිහිදොරකට සම්බන්ධ විය"
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr "සරල දැලැස් බිහිදොරක් ආරම්භ කෙරේ"
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr "නොදන්නා දැලැසකි"
+
+#: ../src/view/frame/activitiestray.py:211
+msgid "Decline"
+msgstr "ක්‍රමයෙන් පිරිහෙනවා"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:107
+msgid "Freeform"
+msgstr "නිදහස් පෝර්මය"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:189
+msgid "Ring"
+msgstr "කවය"
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:334
+msgid "Spiral"
+msgstr "සර්පිලය"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:401
+msgid "Box"
+msgstr "පෙට්ටිය"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:442
+msgid "Triangle"
+msgstr "ත්‍රිකෝණය"
+
+#: ../src/view/home/favoritesview.py:295
+msgid "Registration Failed"
+msgstr "ලියාපදිංචිය අසමත් විය"
+
+#: ../src/view/home/favoritesview.py:296
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/view/home/favoritesview.py:298
+msgid "Registration Successful"
+msgstr "ලියාපදිංචිය සාර්ථක විය"
+
+#: ../src/view/home/favoritesview.py:299
+msgid "You are now registered with your school server."
+msgstr "ඔබ දැන් ඔබගේ පාසල් සේවාදායකය සමඟ ලියාපදිංචි වී ඇත."
+
+#: ../src/view/home/favoritesview.py:420
+msgid "Settings"
+msgstr "සිටුවම්"
+
+#: ../src/view/home/favoritesview.py:425
+msgid "Restart"
+msgstr "යළි ආරම්භ කරන්න"
+
+#: ../src/view/home/favoritesview.py:430
+msgid "Shutdown"
+msgstr "වසා දමන්න"
+
+#: ../src/view/home/favoritesview.py:436
+msgid "Register"
+msgstr "ලියාපදිංචි කරන්න"
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr "ආරම්භවේ..."
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr "නවත්වන්න"
+
+#. TRANS: Action label for starting an entry.
+#: ../src/view/palettes.py:104 ../src/journal/journaltoolbox.py:402
+#: ../src/journal/palettes.py:59
+msgid "Start"
+msgstr "ආරම්භ කරන්න"
+
+#: ../src/view/palettes.py:138
+msgid "Remove favorite"
+msgstr "අභිරුචිය ඉවත් කරන්න"
+
+#: ../src/view/palettes.py:142
+msgid "Make favorite"
+msgstr "අභිරුචියක් කරන්න"
+
+#: ../src/view/palettes.py:191
+msgid "Show contents"
+msgstr "අන්තර්ගතය පෙන්වන්න"
+
+#: ../src/view/palettes.py:215
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB ඉතිරියි"
+
+#: ../src/journal/journaltoolbox.py:62
+msgid "Search"
+msgstr "සෙවිමට"
+
+#: ../src/journal/journaltoolbox.py:119
+msgid "Anytime"
+msgstr "ඕනෑම වෙලාවක"
+
+#: ../src/journal/journaltoolbox.py:121
+msgid "Today"
+msgstr "අද"
+
+#: ../src/journal/journaltoolbox.py:123
+msgid "Since yesterday"
+msgstr "ඊයේ සිට"
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/journal/journaltoolbox.py:125
+msgid "Past week"
+msgstr "පසුගිය සතිය"
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/journal/journaltoolbox.py:127
+msgid "Past month"
+msgstr "පසුගිය මාසය"
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/journal/journaltoolbox.py:129
+msgid "Past year"
+msgstr "පසුගිය වසර"
+
+#: ../src/journal/journaltoolbox.py:136
+msgid "Anyone"
+msgstr "ඕනෑම අයෙක්"
+
+#: ../src/journal/journaltoolbox.py:138
+msgid "My friends"
+msgstr "මාගේ මිතුරන්"
+
+#: ../src/journal/journaltoolbox.py:139
+msgid "My class"
+msgstr "මාගේ පන්තිය"
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/journal/journaltoolbox.py:255
+msgid "Anything"
+msgstr "ඕනෑ දෙයක්"
+
+#. TODO: Add "Start with" menu item
+#: ../src/journal/journaltoolbox.py:325 ../src/journal/palettes.py:67
+msgid "Copy"
+msgstr "පිටපත් කරන්න"
+
+#: ../src/journal/collapsedentry.py:248 ../src/journal/expandedentry.py:176
+#: ../src/journal/palettes.py:51
+msgid "Untitled"
+msgstr "ශීර්ෂ පාඨ නොමැති"
+
+#: ../src/journal/journalactivity.py:119 ../src/journal/volumesmanager.py:57
+msgid "Journal"
+msgstr "ජ'නලය"
+
+#: ../src/journal/expandedentry.py:222
+msgid "No preview"
+msgstr "පූර්වදර්ශනයක් නැත"
+
+#: ../src/journal/expandedentry.py:241
+msgid "Participants:"
+msgstr "සහභාගිවන්නන්:"
+
+#: ../src/journal/expandedentry.py:266
+msgid "Description:"
+msgstr "විස්තරය:"
+
+#: ../src/journal/expandedentry.py:292
+msgid "Tags:"
+msgstr "හැඳුනුම් වදන්:"
+
+#: ../src/journal/objectchooser.py:134
+msgid "Choose an object"
+msgstr "වස්තුවක් තෝරන්න"
+
+#: ../src/journal/objectchooser.py:139
+msgid "Close"
+msgstr "චසාදමන්න"
+
+#: ../src/journal/volumestoolbar.py:93
+msgid "Unmount"
+msgstr "ගලවන්න"
+
+#: ../src/journal/misc.py:95
+msgid "No date"
+msgstr "දිනයක් නැත"
+
+#: ../src/journal/listview.py:39
+msgid "Your Journal is empty"
+msgstr "ඔබගේ ජර්නලය හිස්ය"
+
+#: ../src/journal/listview.py:40
+msgid "No matching entries "
+msgstr "ගැළපෙන නිවේශන නොමැත "
+
+#: ../src/journal/modalalert.py:59
+msgid "Your Journal is full"
+msgstr "ඔබගේ ජර්නලය සම්පූර්ණයෙන් පිරී ඇත"
+
+#: ../src/journal/modalalert.py:63
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"කරුණාකර නව නිවේශන සඳහා ඉඩ ලබා ගැනීමට පැරණි ජර්නල නිවේශන කිහිපයක් මකා දමන්න."
+
+#: ../src/journal/modalalert.py:75
+msgid "Show Journal"
+msgstr "ජර්නලය පෙන්වන්න"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "පසුරු පුවරු වස්තුව: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "ඔබ විසින් සේවාදායකයක් ඇතුලත් කළ යුතුය."
+
+#~ msgid "Control Panel"
+#~ msgstr "පාලක පුවරුව"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "off"
+#~ msgstr "අක්‍රීය කරන්න"
+
+#~ msgid "on"
+#~ msgstr "සක්‍රීය කරන්න"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "අවසර දිය නොහැක. මෙම විධිය ක්‍රියාත්මක කිරීමට ඔබ root විය යුතුය."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "වේලා කලාපය කියවීමේ දෝෂයකි"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "වේලා කලාපය පිටපත් කිරීමේ දෝෂයකි (%s ගෙන්): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "වේලා කලාපයේ අවසර වෙනස් කෙරේ: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "මෙම XO ගැන"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#~ msgid "Add to journal"
+#~ msgstr "ජර්නලයට එක් කරන්න"
+
+#~ msgid "Reboot"
+#~ msgstr "යළි අරඹන්න"
+
+#~ msgid "My Battery life"
+#~ msgstr "මගේ බැටරි ආයු කාලය"
+
+#~ msgid "Battery charging"
+#~ msgstr "බැටරිය ආරෝපණය වේ"
+
+#~ msgid "Battery discharging"
+#~ msgstr "බැටරිය විසර්ජනය වේ"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "බැටරිය සම්පූර්ණයෙන්ම ආරෝපිතයි"
+
+#~ msgid "Share with:"
+#~ msgstr "සමඟ බෙදාගන්න:"
+
+#~ msgid "Private"
+#~ msgstr "පුද්ගලික"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "මගේ වටපිටාව"
+
+#~ msgid "Undo"
+#~ msgstr "පෙර ලෙස"
+
+#~ msgid "Redo"
+#~ msgstr "නැවත කරන්න"
+
+#~ msgid "Paste"
+#~ msgstr "අලවන්න"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s ක්‍රියාකාරකම"
+
+#~ msgid "Keep error"
+#~ msgstr "නබා ගැනීමේ දෝෂයකි"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "තබා ගැනීමේ දෝෂයකි: සියළු වෙනස් කිරීම් නැතිවනු ඇත"
+
+#~ msgid "Don't stop"
+#~ msgstr "නවත්වන්න එපා"
+
+#~ msgid "Stop anyway"
+#~ msgstr "කෙසේ හෝ නවත්වන්න"
+
+#~ msgid "Continue"
+#~ msgstr "පවත්වාගෙන යන්න"
+
+#~ msgid "OK"
+#~ msgstr "හරි"
diff --git a/shell/po/sk.po b/shell/po/sk.po
new file mode 100644
index 0000000..63d4e34
--- /dev/null
+++ b/shell/po/sk.po
@@ -0,0 +1,764 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-25 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/window.py:93 ../src/controlpanel/aboutme/view.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/window.py:125
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/window.py:175 ../src/journal/detailview.py:119
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/window.py:189 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/window.py:192
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:60
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:63
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:92
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:51
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:56 ../src/view/clipboardmenu.py:78
+msgid "Open"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:61 ../src/view/home/HomeBox.py:84
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:83
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:228
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:17
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:31
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:36
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/view/Shell.py:251
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:78
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:80
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:87 ../src/view/palettes.py:120
+#: ../src/journal/journaltoolbox.py:335 ../src/journal/palettes.py:75
+msgid "Erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:117
+msgid "Software Update"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:118
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:122 ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:124 ../src/controlpanel/gui.py:273
+msgid "Later"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:127
+msgid "Check now"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:261
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:262
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:320
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:321
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:159
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:166
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:218 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:221 ../src/view/devices/network/wireless.py:125
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/view/home/MeshBox.py:309 ../src/view/palettes.py:61
+#: ../src/journal/journaltoolbox.py:399 ../src/journal/palettes.py:57
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:314 ../src/view/frame/activitiestray.py:206
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:125
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:128
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:143
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/controlpanel/cmd.py:35
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:48
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:305
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:42 ../src/controlpanel/gui.py:265
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:264
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:268
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:277
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:76
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:87
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:90
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:32
+#: ../src/controlpanel/aboutme/__init__.py:22
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/model.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:55
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:64
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:87
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:96
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:111
+msgid "Sugar:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:126
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:148
+msgid "Copyright and License"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:156
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:163
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:175
+msgid "Full license:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/__init__.py:21
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/datetime/model.py:89
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/datetime/view.py:68
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/frame/model.py:38 ../src/controlpanel/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:114
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:131
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/language/view.py:70
+#: ../src/controlpanel/language/__init__.py:21
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:62
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:82
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:28
+#: ../src/controlpanel/network/__init__.py:21
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:54
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:62
+msgid "Turn of the wireless radio to save battery life"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:75
+msgid "Radio"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:91
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:100
+msgid "Discard network history"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:113
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:122
+msgid "Server:"
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:55
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:84
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:211
+msgid "Decline"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:107
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:189
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:401
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:442
+msgid "Triangle"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:295
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:296
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:298
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:299
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:420
+msgid "Settings"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:425
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:430
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:436
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/view/palettes.py:104 ../src/journal/journaltoolbox.py:402
+#: ../src/journal/palettes.py:59
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:138
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:142
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:191
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:215
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:62
+msgid "Search"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:119
+msgid "Anytime"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:121
+msgid "Today"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:123
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/journal/journaltoolbox.py:125
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/journal/journaltoolbox.py:127
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/journal/journaltoolbox.py:129
+msgid "Past year"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:136
+msgid "Anyone"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:138
+msgid "My friends"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:139
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/journal/journaltoolbox.py:255
+msgid "Anything"
+msgstr ""
+
+#. TODO: Add "Start with" menu item
+#: ../src/journal/journaltoolbox.py:325 ../src/journal/palettes.py:67
+msgid "Copy"
+msgstr ""
+
+#: ../src/journal/collapsedentry.py:248 ../src/journal/expandedentry.py:176
+#: ../src/journal/palettes.py:51
+msgid "Untitled"
+msgstr ""
+
+#: ../src/journal/journalactivity.py:119 ../src/journal/volumesmanager.py:57
+msgid "Journal"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:222
+msgid "No preview"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:241
+msgid "Participants:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:266
+msgid "Description:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:292
+msgid "Tags:"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:134
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:139
+msgid "Close"
+msgstr ""
+
+#: ../src/journal/volumestoolbar.py:93
+msgid "Unmount"
+msgstr ""
+
+#: ../src/journal/misc.py:95
+msgid "No date"
+msgstr ""
+
+#: ../src/journal/listview.py:39
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/journal/listview.py:40
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/journal/modalalert.py:59
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/journal/modalalert.py:63
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/journal/modalalert.py:75
+msgid "Show Journal"
+msgstr ""
diff --git a/shell/po/sl.po b/shell/po/sl.po
new file mode 100644
index 0000000..6981824
--- /dev/null
+++ b/shell/po/sl.po
@@ -0,0 +1,1098 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-02-21 00:30-0500\n"
+"PO-Revision-Date: 2009-02-28 04:26-0500\n"
+"Last-Translator: Denis Oštir <denis.ostir@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "O meni"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Vpisati morat ime."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "pisalo: barva=%s odtenek=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "pisalo: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "zapolni: barva=%s odtenek=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "zapolni: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Napačno določena sprememba barve"
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Napačno določena barva"
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "Ime:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Klikni za spremembo barve:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "O mojem računalniku"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:26
+msgid "Not available"
+msgstr "Ni na voljo"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:59
+msgid "Identity"
+msgstr "Identiteta"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:68
+msgid "Serial Number:"
+msgstr "Serijska številka:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:90
+msgid "Software"
+msgstr "Program"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:99
+msgid "Build:"
+msgstr "Različica:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:114
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:130
+msgid "Firmware:"
+msgstr "Firmware:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:145
+msgid "Wireless Firmware:"
+msgstr "Brezžična oprema:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:168
+msgid "Copyright and License"
+msgstr "Lastnik pravic"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:176
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr "© 2008 One Laptop per Child Association Inc, Red Hat Inc in sodelavci."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:183
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Sugar je grafični vmesnik, ki ga uporabljate. Je brezplačen, avtorske "
+"pravice glede njegove uporabe pa ureja GNU General Public License. Zato ga "
+"lahko spreminjate in/ali distribuirate, a pod nekaterimi pogoji, zapisanimi "
+"v omenjeni licenci."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:195
+msgid "Full license:"
+msgstr "Licenčne pravice:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Datum in ura"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Napaka: časovno območje ne obstaja."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:19
+msgid "Timezone"
+msgstr "Časovno območje"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Okvir"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Vrednost mora biti številka."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "nikoli"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "takojšnji"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s sekund"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Zamik aktivacije"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Kot"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Rob"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:32
+msgid "Language"
+msgstr "Jezik"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Dostop do ~/.i18n ni mogoče. Ustvari standardne nastavitve."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Jezika za kodo=%s ni bilo mogoče določiti."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Oprosti, ne govorim '%s'."
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Omrežje"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Neznana država."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Napaka pri določanju stanja radijske povezave (vključen/izključen)."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Napaka pri uporabi podatka 0/1."
+
+#: ../extensions/cpsection/network/view.py:56
+msgid "Wireless"
+msgstr "Brezžično"
+
+#: ../extensions/cpsection/network/view.py:64
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Izklopi brezžično radijsko povezavo za podaljšanje trajanja baterije"
+
+#: ../extensions/cpsection/network/view.py:77
+msgid "Radio"
+msgstr "Radijska povezava:"
+
+#: ../extensions/cpsection/network/view.py:93
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "Zavrži zgodovino mreže, če imate težave pri povezavi z mrežo"
+
+#: ../extensions/cpsection/network/view.py:102
+msgid "Discard network history"
+msgstr "Zavrži zgodovino mreže"
+
+#: ../extensions/cpsection/network/view.py:115
+msgid "Collaboration"
+msgstr "Sodelovanje"
+
+#: ../extensions/cpsection/network/view.py:123
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"Strežnik predstavlja sobo v kateri se nahajate. Uporabniki na istem "
+"strežniku se lahko vidijo, tudi če niso priključeni na isto omrežje."
+
+#: ../extensions/cpsection/network/view.py:133
+msgid "Server:"
+msgstr "Strežnik:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Energija"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Napaka pri samodejni rabi ukaza pm, uporabi izklop/vklop."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Napaka pri ekstremni vrednosti ukaza pm, uporabi izklop/vklop."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Nazdor porabe električne energije"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+"Samodejni nadzor porabe električne energije (podalšuje življenjsko dobo "
+"baterije)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Ekstremni nadzor porabe električne energije (ugasnjen radijski del, podaljša "
+"življenjsko dobo baterije)"
+
+#: ../extensions/deviceicon/battery.py:56
+msgid "My Battery"
+msgstr "Moja baterija"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Odstranjeno"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Polnjenje"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Baterija je skoraj prazna"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "Ostaja %(hour)d:%(min).2d"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Polno"
+
+#: ../extensions/deviceicon/network.py:40
+#, python-format
+msgid "IP address: %s"
+msgstr "IP naslov: %s"
+
+#: ../extensions/deviceicon/network.py:104
+msgid "Disconnect..."
+msgstr "Prekini ... "
+
+#: ../extensions/deviceicon/network.py:109
+#: ../src/jarabe/desktop/meshbox.py:247
+msgid "Connecting..."
+msgstr "Povezujem ..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:113
+#: ../extensions/deviceicon/network.py:166
+#: ../src/jarabe/desktop/meshbox.py:253
+msgid "Connected"
+msgstr "Povezan"
+
+#: ../extensions/deviceicon/network.py:126
+msgid "Channel"
+msgstr "Kanal"
+
+#: ../extensions/deviceicon/network.py:141
+msgid "Wired Network"
+msgstr "Žično omrežje"
+
+#: ../extensions/deviceicon/network.py:169
+msgid "Speed"
+msgstr "Hitrost"
+
+#: ../extensions/deviceicon/speaker.py:46
+msgid "My Speakers"
+msgstr "Moji zvočniki"
+
+# malo težko je UNMUTE prevest drugače
+#: ../extensions/deviceicon/speaker.py:128
+msgid "Unmute"
+msgstr "Glasno"
+
+#: ../extensions/deviceicon/speaker.py:131
+msgid "Mute"
+msgstr "Tiho"
+
+#: ../extensions/globalkey/screenshot.py:50
+msgid "Screenshot"
+msgstr "Slika zaslona"
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr "Nadomestni spletni naslov"
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"Barva ikone XO, ki jo uporabljate na celotnem namizju. Zaporedje je "
+"sestavljeno iz barve črte in barve polnila v formatu RGB. Primer: "
+"#AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr "Zamik pri kotu"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr "Zamik pri prikazu okvirja ob premiku v kot"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Zamik pri prikazu okvirja ob premiku na rob"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr "Zamik ob robu"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr "Izgled priljubljenih"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr "Način ponovitve priljubljenih"
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"Če je oznaka DA, bo Sugar omogočil vidnost drugim uporabnikom na strežniku "
+"Jabber"
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Jabber Server"
+msgstr "Strežnik Jabber"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Layout of the favorites view."
+msgstr "Izgled pogleda priljubljenih"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Power Automatic"
+msgstr "Samodejno upravljanje z elektriko"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Power Automatic."
+msgstr "Samodejno upravljanje z elektriko"
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Power Extreme"
+msgstr "Ekstremno upravljanje z elektriko"
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Power Extreme."
+msgstr "Ekstremno upravljanje z elektriko"
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Publish to Gadget"
+msgstr "Objavi v napravi"
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Setting for muting the sound device."
+msgstr "Nastavitev utišanja zvočne naprave"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Sound Muted"
+msgstr "Zvok utišan"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Timezone setting for the system."
+msgstr "Nastavitev časovnega pasu za sistem"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Url of the jabber server to use."
+msgstr "Spletni naslov uporabljenega strežnika jabber"
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Url where the backup is saved to."
+msgstr "Spletni naslov arhiva"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "User Color"
+msgstr "Barva uporabnika"
+
+#: ../data/sugar.schemas.in.h:24
+msgid "User Name"
+msgstr "Uporabnikovo ime"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "User name that is used throughout the desktop."
+msgstr "Uporabnikovo ime, ki se uporablja po celotnem namizju."
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Volume Level"
+msgstr "Raven glasnosti"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Volume level for the sound device."
+msgstr "Raven glasnosti za zvočno napravo."
+
+#: ../data/sugar.schemas.in.h:28
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"V načinu nadaljevanja s klikom na priljubljeno ikono v aktivnosti "
+"nadaljujete pri zadnji shranjeni spremembi."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"nadzorna plošča programa sugar: OPOZORILO, najdena je več kot ena možnost z "
+"enakim imenom: %s modul: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "nadzorna plošča programa sugar: ključ=%s ni veljavna možnost"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "nadzorna plošča programa sugar: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Uporaba: nadzorna plošča programa sugar [ možnost ] tipka [ ukaz ... ] \n"
+" Nadzor v okolju sugar. \n"
+" Možnosti: \n"
+" -h prikaži to sporočilo in končaj \n"
+" -l prikaži vse možnosti, ki so na voljo \n"
+" -h tipka prikaži informacije za to tipko \n"
+" -g tipka pridobi trenutno vrednost tipke \n"
+" -s tipka nastavi trenutno vrednost tipke \n"
+" -c tipka izbriši trenurno vrednost tipke \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Za uveljavitev sprememb je potreben ponovni zagon programa sugar.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:275
+msgid "Warning"
+msgstr "Opozorilo"
+
+#: ../src/jarabe/controlpanel/gui.py:276
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Sprembe zahtevajo ponovni zagon"
+
+#: ../src/jarabe/controlpanel/gui.py:279
+msgid "Cancel changes"
+msgstr "Prekliči spremembe"
+
+#: ../src/jarabe/controlpanel/gui.py:284 ../src/jarabe/desktop/homebox.py:113
+msgid "Later"
+msgstr "Kasneje"
+
+#: ../src/jarabe/controlpanel/gui.py:288
+msgid "Restart now"
+msgstr "Ponovni zagon"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "Končano"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:111
+#: ../src/jarabe/frame/activitiestray.py:687
+#: ../src/jarabe/frame/activitiestray.py:766
+#: ../src/jarabe/frame/activitiestray.py:794
+msgid "Cancel"
+msgstr "Prekliči"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:338
+msgid "Ok"
+msgstr "V redu"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:114
+msgid "Freeform"
+msgstr "Prostoročno"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:196
+msgid "Ring"
+msgstr "Obroč"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:332
+msgid "Spiral"
+msgstr "Spirala"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:399
+msgid "Box"
+msgstr "Okvir"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:440
+msgid "Triangle"
+msgstr "Trikotnik"
+
+#: ../src/jarabe/desktop/favoritesview.py:329
+msgid "Registration Failed"
+msgstr "Registracija ni uspela"
+
+#: ../src/jarabe/desktop/favoritesview.py:330
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Registration Successful"
+msgstr "Uspešna registracija"
+
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "You are now registered with your school server."
+msgstr "Vpisan si v šolski strežnik."
+
+#: ../src/jarabe/desktop/favoritesview.py:668
+msgid "Register"
+msgstr "Registracija"
+
+#: ../src/jarabe/desktop/homebox.py:67
+msgid "Confirm erase"
+msgstr "Potrdi brisanje"
+
+#: ../src/jarabe/desktop/homebox.py:69
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Potrdi brisanje: Želiš dokočno izbrisati %s?"
+
+#: ../src/jarabe/desktop/homebox.py:73 ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Obdrži"
+
+#: ../src/jarabe/desktop/homebox.py:76
+#: ../src/jarabe/journal/journaltoolbox.py:357
+#: ../src/jarabe/journal/palettes.py:112 ../src/jarabe/view/palettes.py:153
+msgid "Erase"
+msgstr "Izbriši"
+
+#: ../src/jarabe/desktop/homebox.py:106
+msgid "Software Update"
+msgstr "Nadgradnja programa"
+
+#: ../src/jarabe/desktop/homebox.py:107
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"Nadgradite aktivnosti, da zagotovite ustreznost z novo programsko opremo."
+
+#: ../src/jarabe/desktop/homebox.py:116
+msgid "Check now"
+msgstr "Preveri zdaj"
+
+#: ../src/jarabe/desktop/homebox.py:233
+msgid "List view"
+msgstr "Seznam"
+
+#: ../src/jarabe/desktop/homebox.py:234
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:296
+msgid "Favorites view"
+msgstr "Priljubljene"
+
+#: ../src/jarabe/desktop/homebox.py:297
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr "Tip ključa:"
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr "Tip prepoznave:"
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr "WPA in WPA2 Osebni ključ"
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr "Varovanje brezžičnega omrežja:"
+
+#: ../src/jarabe/desktop/meshbox.py:131
+msgid "Connect"
+msgstr "Poveži"
+
+#: ../src/jarabe/desktop/meshbox.py:135
+msgid "Disconnect"
+msgstr "Prekini"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:441
+#: ../src/jarabe/frame/activitiestray.py:711
+#: ../src/jarabe/journal/journaltoolbox.py:425
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:66
+msgid "Resume"
+msgstr "Nadaljuj"
+
+#: ../src/jarabe/desktop/meshbox.py:446
+#: ../src/jarabe/frame/activitiestray.py:227
+msgid "Join"
+msgstr "Pridruži se"
+
+#: ../src/jarabe/desktop/schoolserver.py:34
+msgid "Cannot obtain data needed for registration."
+msgstr "Ne morem pridobiti podatkov, potrebnih za registracijo."
+
+#: ../src/jarabe/desktop/schoolserver.py:51
+msgid "Cannot connect to the server."
+msgstr "Povezava s strežnikom ni mogoča."
+
+#: ../src/jarabe/desktop/schoolserver.py:56
+msgid "The server could not complete the request."
+msgstr "Strežnik ne more izpolniti zahteve."
+
+#: ../src/jarabe/frame/activitiestray.py:232
+#: ../src/jarabe/frame/activitiestray.py:659
+msgid "Decline"
+msgstr "Zavrni"
+
+#: ../src/jarabe/frame/activitiestray.py:612
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:614
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:616
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:633
+#, python-format
+msgid "%s of %s"
+msgstr "%s od %s"
+
+#: ../src/jarabe/frame/activitiestray.py:644
+#, python-format
+msgid "Transfer from %r"
+msgstr "Prenesi z %r"
+
+#: ../src/jarabe/frame/activitiestray.py:654
+msgid "Accept"
+msgstr "Sprejmi"
+
+#: ../src/jarabe/frame/activitiestray.py:677
+#: ../src/jarabe/frame/activitiestray.py:784
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:755
+#, python-format
+msgid "Transfer to %r"
+msgstr "Prenesi na %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr "Odstrani"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "Odpri"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "Odpri z"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s strižem"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:36
+msgid "Neighborhood"
+msgstr "Soseščina"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:38
+msgid "Group"
+msgstr "Skupina"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:40
+msgid "Home"
+msgstr "Domov"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:42
+msgid "Activity"
+msgstr "Aktivnost"
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "Klikni za spremembo barve:"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Nazaj"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "Naslednji"
+
+#: ../src/jarabe/journal/collapsedentry.py:258
+#: ../src/jarabe/journal/expandedentry.py:159
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "Neimenovan"
+
+#: ../src/jarabe/journal/expandedentry.py:205
+msgid "No preview"
+msgstr "Predogled ni na voljo"
+
+#: ../src/jarabe/journal/expandedentry.py:224
+msgid "Participants:"
+msgstr "Udeleženci:"
+
+#: ../src/jarabe/journal/expandedentry.py:247
+msgid "Description:"
+msgstr "Opis:"
+
+#: ../src/jarabe/journal/expandedentry.py:273
+msgid "Tags:"
+msgstr "Oznake:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Beležka"
+
+#: ../src/jarabe/journal/journaltoolbox.py:65
+msgid "Search"
+msgstr "Išči"
+
+#: ../src/jarabe/journal/journaltoolbox.py:124
+msgid "Anytime"
+msgstr "Kadarkoli"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Today"
+msgstr "Danes"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Since yesterday"
+msgstr "Od včeraj"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Past week"
+msgstr "V zadnjem tednu"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past month"
+msgstr "V zadnjem mesecu"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past year"
+msgstr "V zadnjem letu"
+
+#: ../src/jarabe/journal/journaltoolbox.py:141
+msgid "Anyone"
+msgstr "Kdorkoli"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "My friends"
+msgstr "Moji prijatelji"
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "My class"
+msgstr "Moj razred"
+
+# TRANS: Item in a combo box that filters by entry type.
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:271
+msgid "Anything"
+msgstr "Karkoli"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:347
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "Kopiraj"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:75 ../src/jarabe/view/palettes.py:135
+msgid "Start"
+msgstr "Zaženi"
+
+#: ../src/jarabe/journal/listview.py:40
+msgid "Your Journal is empty"
+msgstr "Tvoja beležka je prazna"
+
+#: ../src/jarabe/journal/listview.py:41
+msgid "No matching entries "
+msgstr "Ne najdem vsebine za "
+
+#: ../src/jarabe/journal/listview.py:369
+msgid "Clear search"
+msgstr "Počisti iskanje"
+
+#: ../src/jarabe/journal/misc.py:91
+msgid "No date"
+msgstr "Brez datuma"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Tvoja beležka je polna"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr "Izbriši starejše vpise v beležko, da narediš prostor za nove."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Prikaži beležko"
+
+#: ../src/jarabe/journal/objectchooser.py:147
+msgid "Choose an object"
+msgstr "Izberi predmet"
+
+#: ../src/jarabe/journal/objectchooser.py:152
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Zapri"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr "Nadaljuj z"
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr "Začni z"
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr "Pošlji"
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr "Poglej podrobnosti"
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr "Prisoten ni noben prijatelj"
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr "Na voljo ni nobena veljavna povezava"
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr "Ni aktivnosti za nadaljevanje"
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr "Ni aktivnosti za začetek"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Odstrani prijatelja"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Dodaj prijatelja"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "My Settings"
+msgstr "Moje nastavitve"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Odjava"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "Restart"
+msgstr "Ponovni zagon"
+
+#: ../src/jarabe/view/buddymenu.py:100
+msgid "Shutdown"
+msgstr "Zaustavitev"
+
+#: ../src/jarabe/view/buddymenu.py:135
+#, python-format
+msgid "Invite to %s"
+msgstr "Povabi na %s"
+
+#: ../src/jarabe/view/palettes.py:47
+msgid "Starting..."
+msgstr "Zaganjam ..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:73
+msgid "View Source"
+msgstr "Poglej izvor"
+
+#: ../src/jarabe/view/palettes.py:84
+msgid "Stop"
+msgstr "Ustavi"
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Remove favorite"
+msgstr "Odstrani priljubljeno"
+
+#: ../src/jarabe/view/palettes.py:175
+msgid "Make favorite"
+msgstr "Nastavi priljubljeno"
+
+#: ../src/jarabe/view/palettes.py:238
+msgid "Show contents"
+msgstr "Prikaži vsebino"
+
+#: ../src/jarabe/view/palettes.py:260 ../src/jarabe/view/palettes.py:309
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB prosto"
+
+#: ../src/jarabe/view/palettes.py:285
+msgid "Unmount"
+msgstr "Odstrani"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Primer izvora"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Izvor"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "Izvor kompleta aktivnosti"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "Poglej vir: %r"
+
+#~ msgid "Document"
+#~ msgstr "Dokument"
+
+#~ msgid "Resume by default"
+#~ msgstr "Vedno nadaljuj"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Tip kodiranja:"
+
+#~ msgid "Disconnecting..."
+#~ msgstr "Prekinjam ..."
+
+#~ msgid "Mesh Network"
+#~ msgstr "Omrežje Mesh"
+
+#~ msgid "Disconnected"
+#~ msgstr "Odklopljen"
+
+#~ msgid "About my XO"
+#~ msgstr "O mojem XO"
+
+#~ msgid "Mesh"
+#~ msgstr "Mesh"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Povezan na šolski Mesh portal"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Iskanje šolskega Mesh portala ..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Povezan na XO Mesh portal"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "Iskanje XO Mesh portala"
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Povezan v enostavno Mesh omrežje"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Ustvarjam enostavno Mesh omrežje"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Neznano Mesh omrežje"
+
+#~ msgid "Settings"
+#~ msgstr "Nastavitve"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Predmet na odložišču: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "Vpisati moraš strežnik."
+
+#~ msgid "Control Panel"
+#~ msgstr "Nadzorna plošča"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
diff --git a/shell/po/sq.po b/shell/po/sq.po
new file mode 100644
index 0000000..bf4ba67
--- /dev/null
+++ b/shell/po/sq.po
@@ -0,0 +1,1215 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-26 00:31-0400\n"
+"PO-Revision-Date: 2009-06-18 11:32+0100\n"
+"Last-Translator: Heroid <heroid@ayih.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.3.0\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Rreth Meje"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Vetem emri duhet shkruar"
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "goditje: color=%s hue=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "goditje: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "mbushje: color=%s hue=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "mbushje: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "Emri:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Kliko për ta ndrryshuar ngjyrën:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Rreth Kompjuterit tim"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Nuk gjindet"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Identiteti"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Numri Serik:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Softueri"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Ndërto:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Liqencë me Leje Kopjimi"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Liqencë e plotë:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Data & Koha"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Gabim zona e kohës nuk ekziston"
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr "Zona e kohës"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Fërmi"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Shifra duhet të jetë integer."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "kurrë"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s sekonda"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Koha e aktivizimit"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Qoshe"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Skaj"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Gjuhë"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Më vjen keq unë nuk flas ´%s´."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Rrjet"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Shtet i panjohur."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Pa tela"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Radio"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Server:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Menagjimi i energjisë"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/updater/__init__.py:21
+#, fuzzy
+msgid "Software update"
+msgstr "Përditsim Softueri"
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+#, fuzzy
+msgid "None"
+msgstr "E kryer"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Baterija Ime"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "E fshirë"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Duke u mbushur"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Shumë pak energji ka mbetur"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(orë)d:%(min).2d kanë mbetur"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "I mbushur"
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr "IP addresa: %s"
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr "Shkëputu..."
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:261
+msgid "Connecting..."
+msgstr "Duke u lidhur..."
+
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:267
+msgid "Connected"
+msgstr "I lidhur"
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr "Kanali"
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr "Rrjet i Quditshëm"
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr "Shpejtësija"
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Spikerët e mi"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Lësho zërin"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Hiqe zërin"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Grupi"
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Shtëpija"
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Aktiviteti"
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr "Sekuencë ekrani"
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr "Rikthe URL-në"
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr "Niveli i Volumit"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr "Niveli i volumit për pajisjen"
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr "Paralajmërim"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Ndrryshimet kanë nevojë për rinisje"
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr "Anulo ndrryshimet"
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Më vonë"
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr "Rinis tani"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "E kryer"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr "Anulo"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr "Në rregull"
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr "Konfirmo fshirjen"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Konfirmo fshirjen: A doni që përgjithmonë ta fshini %s?"
+
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Mbaje"
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:406
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr "Fshije"
+
+#: ../src/jarabe/desktop/activitieslist.py:427
+msgid "Remove favorite"
+msgstr "Fshije favoritin"
+
+#: ../src/jarabe/desktop/activitieslist.py:431
+msgid "Make favorite"
+msgstr "Bëje favorit"
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Formë e lirë"
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Unazë"
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:334
+msgid "Spiral"
+msgstr "Spirale"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:401
+msgid "Box"
+msgstr "Kuti"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:442
+msgid "Triangle"
+msgstr "Trekëndësh"
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr "Regjistrimi Dsëhtoi"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr "Regjistrimi u krye me Sukses"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr "Ju jeni regjistruar në serverin e shkollës suaj."
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr "Regjistrohu"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Përditsim Softueri"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Shiqo tani"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Pamje në listë"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Shfaq Favoritët"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr "Sigurija e rrjetit pa tela:"
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr "Lidhu"
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr "Shkëputu"
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:463
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr "Vazhdo"
+
+#: ../src/jarabe/desktop/meshbox.py:468
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr "Bashkohu"
+
+#: ../src/jarabe/desktop/schoolserver.py:34
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:51
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:56
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr "Mos prano"
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr "%s prej %s"
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr "Transfer nga %r"
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr "Prano"
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr "Pusho"
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr "Transfer tek %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr "Fshije"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "Hape"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "Hape me"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Lagjja"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "Kliko për ta ndrruar ngjyrën:"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Prapa"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "Përpara"
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "E paemërtuar"
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr "Pa provë"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr "Pa datë"
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr "Përshkrimi:"
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Ditar"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Kërko"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "Gjithnjë"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Sot"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Që dje"
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Java e kaluar"
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Muaji i kaluar"
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Viti i kaluar"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Gjithkush"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Shokët e mi"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Klasa ime"
+
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Gjithqka"
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "Kopjo"
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr "Fillo"
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr "Ditari juaj është i thatë"
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr "Pastro kërkimin"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Ditari yt është mbushur"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"Ju lutem fshini disa gjëra nga Ditari juaj për të lëshuar vend për të reja."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Shfaq ditarin"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Zgjidh një objekt"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Mbyll"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr "Vazhdo me"
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr "Fillo me"
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr "Qo në"
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Fshije mikun"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Bëje mik"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Ndale"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Dil"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr " Fto në %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Duke filluar..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr "Shfaq Burimin"
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr "Ndalo"
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr "Shfaq përmbajtjen"
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:218
+msgid "Unmount"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Burimi"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#~ msgid "Restart"
+#~ msgstr "Rinis"
diff --git a/shell/po/sv.po b/shell/po/sv.po
new file mode 100644
index 0000000..b70c9d4
--- /dev/null
+++ b/shell/po/sv.po
@@ -0,0 +1,1339 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-09-05 00:31-0400\n"
+"PO-Revision-Date: 2010-02-03 22:14+0200\n"
+"Last-Translator: Nicci Manns <nicci@saunalahti.fi>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 2.0.1\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Om mig"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Du måste ange ett namn."
+
+# Varför ska detta översättas? Är det inte direkta kommandon till grafikuppritaren?
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "stroke: color=%s hue=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "stroke: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "fill: color=%s hue=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "fill: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Error in specified color modifiers."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Fel i angivna färger."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "Namn:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Klicka för att ändra din färg:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Om min dator"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Finns inte tillgänglig"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Identitet"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Serienummer:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Programvara"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Byggnummer:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sockerversion:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Fast mjukvara:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "Trådlös fast mjukvara:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Copyright och Licens"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Socker är det grafiska användargränssnittet som du använder just nu. Socker "
+"är fri programvara och licenserad under GNU GPL vilket innebär att du fritt "
+"får ändra programmet och/eller sprida vidare kopior av programmet."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Detaljerad licens:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Datum och tid"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Fel: Tidszonen finns inte."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr "Tidszon"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Ram"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Talet måste vara ett heltal."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "aldrig"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "direkt"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "efter %s sekunder"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Tid tills aktivering"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Hörn"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Kant"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "Tangentbord"
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr "Tangentbordstyp"
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr "Tangent för att växla mellan tangentbordstyper"
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr "Tangentbordstyp"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Språk"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Kunde inte komma åt ~/.i18n. Skapar standardinställningar."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Kunde inte avgöra vilket språk det är som har koden %s."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Tyvärr så pratar jag inte '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"Lägg till språk i den ordningen du förstår dem. Finns det inte en "
+"översättning i det översta språket kommer texten visas i den näst översta "
+"osv."
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Nätverk"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Status är okänd."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Fel i angiven trådlös nätverksinställning. Använd på eller av."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Fel i angivet argument. Använd 0/1"
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Trådlöst nätverk"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Stäng av det trådlösa nätverket för att få batteriet att räcka längre"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Trådlöst nätverk"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+"Ta bort nätverkshistoriken om du har problem med att ansluta till ett "
+"nätverk"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Ta bort nätverkshistorik"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Samarbete"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"Servern motsvarar det rum som du är i; de som är på samma server kan se "
+"varandra även när de inte är på samma nätverk."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Server:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Ström"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Fel i angiven strömbesparingsinställning. Använd på eller av."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Fel i angiven extrem strömbesparingsinställning. Använd på eller av."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Strömhantering"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Automatisk strömhantering (förlänger tiden som batteriet varar)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Extrem strömhantering (stänger av det trådlösa nätverket, ökar "
+"batterilivslängden)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Mjukvaruuppdatering"
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"Mjukvaruuppdateringar rättar till fel, tar bort säkerhetsrisker och lägger "
+"till nya funktioner."
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr "Kontrollerar %s"
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr "Laddar ned %s..."
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr "Uppdaterar %s..."
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr "Den senaste versionen av mjukvaran är redan installerad"
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "Det finns %s tillgänglig uppdatering"
+msgstr[1] "Det finns %s tillgängliga uppdateringar"
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr "Letar efter uppdateringar..."
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr "Installerar uppdateringar..."
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s uppdatering installerades"
+msgstr[1] "%s uppdateringar installerades"
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr "Installera de valda objekten"
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr "Nedladdningsstorlek: %s"
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "Frän version %(current)d till %(new)s (Storlek: %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+msgid "None"
+msgstr "Inget"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr "1 kb"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f kb"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Mitt batteri"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Borttaget"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Laddar"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Batteriet är nästan slut"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d återstår"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Fulladdad"
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr "IP-adress: %s"
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr "Avbryt anslutning..."
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr "Skapa ett nytt trådlöst nätverk"
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:264
+msgid "Connecting..."
+msgstr "Kopplar upp..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:270
+msgid "Connected"
+msgstr "Ansluten"
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr "Kanal"
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr "Trådbundet nätverk"
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr "Hastighet"
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr "%ss nätverk %s"
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Mina högtalare"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Slå på ljud"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Stäng av ljud"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr "Mesh"
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Grupp"
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Hem"
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Aktivitet"
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr "Skärmbild"
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "\"%s\"-Skärmbild"
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr "URL för säkerhetskopiering"
+
+# Error in original string! Never heard of "rbg colors".
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"Den färg som används för XO-ikonen överallt på skrivbordet. Det skall vara "
+"en sträng som består av streckfärg och fyllnadsfärg båda formaterade som "
+"rgb-färger. Exempel: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr "Hörnfördröjning"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr "Fördröjning innan aktivering av ramen med hjälp av hörnen."
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Fördröjning innan aktivering av ramen med hjälp av kanterna."
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr "Kantfördröjning"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr "Utseende på favoriter"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr "Fortsättningsläge för favoriter"
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"Om SANT, så gör Sugar så att vi kan sökas fram av andra användare av jabber-"
+"servern."
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "Om SANT, så kommer Sugar att visa ett utloggningsalternativ."
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr "Jabber-server"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr "Tangentbordstyp"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr "Tangentbordstyp"
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr "Tangentbordsalternativ"
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr "Hur favoritvyn ser ut."
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+"Lista över tangentbordslayouter. Varje post bör vara i formen "
+"layout(variant)"
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr "Lista över Tangentbordsval."
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr "Automatisk ström"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr "Automatisk ström."
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr "Extrem ström"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr "Extrem ström."
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr "Publicera till Gadget"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr "Inställningar för att stänga av ljudenheten."
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr "Visa utloggning"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr "Ljud avstängt"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr "Tangentbordstyp som kommer att användas:"
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr "Systemets tidszonsinställning."
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr "URL för den jabber-server som skall användas."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr "URL för den plats där säkerhetskopieringar skall lagras."
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr "Användarfärg"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr "Användarnamn"
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr "Det användarnamn som används överallt på skrivbordet."
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr "Volymnivå"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr "Ljudenhetens volymnivå."
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"Om fortsättningsläge är aktiverat så kommer ett klick på en favoritikon "
+"innebära att den senaste posten för den aktiviteten kommer att återupptas."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: VARNING, Hittade mer än ett alternativ med samma namn: "
+"%s modul: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: key=%s är inte ett giltigt val."
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Användning: sugar-control-panel [ val ] nyckel [ parametrar ... ] \n"
+" Ställ in Sockermiljön. \n"
+" Val: \n"
+" -h visar hjälpmeddelande och avslutar. \n"
+" -l listar upp alla möjliga val \n"
+" -h nyckel Visar information om nyckeln \n"
+" -g nyckel Hämtar nuvarande värde på nyckel \n"
+" -s nyckel Sätter nuvarande värde på nyckel \n"
+" -c nyckel Rensar nuvarande värde på nyckel \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "För att förändringarna ska träda i kraft behöver du starta om Socker.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr "Varning"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Ändringarna kräver omstart"
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr "Ångra ändringar"
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Senare"
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr "Starta om nu"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "Klar"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr "Avbryt"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr "Ok"
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr "Rubrik"
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr "Version"
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr "Datum"
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr "Version %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr "Bekräfta borttagning"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Bekräfta borttagning: Vill du verkligen ta bort %s för alltid?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Spara"
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:407
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr "Ta bort"
+
+#: ../src/jarabe/desktop/activitieslist.py:428
+msgid "Remove favorite"
+msgstr "Ta bort från favoriter"
+
+#: ../src/jarabe/desktop/activitieslist.py:432
+msgid "Make favorite"
+msgstr "Lägg till till favoriter"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Frihand"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Ring"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Spiral"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Låda"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Triangel"
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr "Registreringen misslyckades"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr "Registreringen lyckades"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr "Du är nu registread hos din skolserver"
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr "Registrera"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Mjukvaruuppdatering"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+"Uppdatera dina aktiviteter så att du är säker på att de fungerar ihop med "
+"din nya mjukvara"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Kontrollera nu"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Listvy"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl> + 2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Favoritvy"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl> + 1"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr "Huvudtyp:"
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr "Verifieringstyp:"
+
+# Uncertain whether Personal here refers to both protocols or WPA2 only.
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr "WPA & WPA2 Personal"
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr "Trådlös säkerhet:"
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr "Anslut"
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr "Avbryt anslutning"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:466
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr "Återuppta"
+
+#: ../src/jarabe/desktop/meshbox.py:471
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr "Gå med i"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "Kunde inte komma åter servern."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "Servern misslyckades med att fullfölja förfrågan."
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr "Avstå"
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+# This really needs a TRANS!
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr "%s av %s"
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr "Överföring från %r"
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr "Godta"
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr "Avvisa"
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr "Överföring till %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:52 ../src/jarabe/view/palettes.py:218
+msgid "Remove"
+msgstr "Ta bort"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "Öppna"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "Öppna med"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s urklipp"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Grannar"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "Klicka för att ändra färg:"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Tillbaka"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "Nästa"
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "Ingen titel"
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr "Ingen förhandsvisning"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr "Typ: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr "Okänd"
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr "Datum: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr "Storlek: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr "Inget datum"
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr "Medverkande:"
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr "Beskrivning:"
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr "Nyckelord:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Dagbok"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Sök"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "När som helst"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Idag"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Sedan igår"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Förra veckan"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Senaste månaden"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Senaste året"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Vem som helst"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Mina vänner"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Mina klasskompisar"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Vad som helst"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "Kopiera"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr "Starta"
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr "Din dagbok är tom."
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr "Kunde inte hitta matchande data"
+
+# Uncertain if this is used to clear the search criteria or the search results. A TRANS would be nice.
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr "Rensa sökning"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Din dagbok är full"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr "Ta bort gamla dagboksinlägg för att få plats med nya."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Visa Dagbok"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Välj ett objekt"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Stäng"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr "Återuppta med"
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr "Börja med"
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr "Skicka till"
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr "Se detaljer"
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr "Inga kompisar närvarande"
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr "Ingen giltig anslutning hittad"
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr "Ingen aktivitet att fortsätta med"
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr "Ingen aktivitet att börja med"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Ta bort kompis"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Bli kompis med"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Stäng av"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Logga ut"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "Mina inställningar"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Bjud in till %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Startar..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr "Se källa"
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr "Avsluta"
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr "Öppna ny"
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr "Visa innehåll"
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB ledigt"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Instanskälla"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Källa"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "Källa för aktivitetspaket"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "Se källa: %r"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr ""
+#~ "Kunde inte komma åt den data som krävs för att genomföra registreringen."
+
+#~ msgid "Unmount"
+#~ msgstr "Avmontera"
+
+#~ msgid "Restart"
+#~ msgstr "Starta om"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; och andra "
+#~ "bidragare."
+
+#~ msgid "Document"
+#~ msgstr "Dokument"
+
+#~ msgid "Resume by default"
+#~ msgstr "Återuppta som förval"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Krypteringstyp:"
+
+#~ msgid "Disconnecting..."
+#~ msgstr "Kopplar ned..."
+
+# only temporarily
+#~ msgid "Mesh Network"
+#~ msgstr "Meshnätverk"
+
+#~ msgid "Disconnected"
+#~ msgstr "Inte ansluten"
+
+#~ msgid "About my XO"
+#~ msgstr "Om min XO"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Ansluten till en skolportal"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Letar efter en skolportal..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Ansluten till en XO-portal"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "Letar efter en XO-portal..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Ansluten till ett enkelt meshnätverk"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Startar ett enkelt meshnätverk..."
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Okänt meshnätverk"
+
+#~ msgid "Settings"
+#~ msgstr "Inställningar"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Kopieringsminne: %s."
+
+#~ msgid ""
+#~ "Extreme power management (disables wireless radio, increases battery life)"
+#~ msgstr ""
+#~ "Extrem strömsparning (stänger av det trådlösa nätverket, allt för att öka "
+#~ "tiden innan batteriet laddas ur)"
+
+#~ msgid "Control Panel"
+#~ msgstr "Kontrollpanel"
diff --git a/shell/po/sw.po b/shell/po/sw.po
new file mode 100644
index 0000000..528f114
--- /dev/null
+++ b/shell/po/sw.po
@@ -0,0 +1,1222 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-09-05 00:31-0400\n"
+"PO-Revision-Date: 2008-11-21 16:06-0500\n"
+"Last-Translator: Fanuel Kalugendo <fanosbert@yahoo.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Kuhusu mimi"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Lazima uingize jina lako"
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Hitilafu kwenye kirekebisha rangi kilichoelezwa"
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Hitilafu kwenye rangi zilizoelezwa"
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "Jina:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+#, fuzzy
+msgid "Click to change your color:"
+msgstr "Bofya kubadilisha rangi:"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Haipo"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Utambulisho"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Serial namba"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Software"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Jenga:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sukari:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Haki miliki na leseni"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Leseni kamili:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Tarehe & Saa"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Fremu"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "mwiko"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s sekunde"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Kona"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Pembeni"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Lugha"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "Haikuweza kufikia ~/.i18n. Tengeneza standard setting"
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Samahani si wezi kuongea '%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Mtandao"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Hali haijulikani"
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Isiyonawiya"
+
+#: ../extensions/cpsection/network/view.py:67
+#, fuzzy
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Zima redio isiyotumiawiya kunusuru maisha ya betri"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Redio"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Seva:"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+# unaweza kusema 'kujichanora' kwa maana ya 'up to date'
+#: ../extensions/cpsection/updater/__init__.py:21
+#, fuzzy
+msgid "Software update"
+msgstr "Ifanye software iwe ya kisasa"
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+#, fuzzy
+msgid "None"
+msgstr "Gotoka"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Betri yangu"
+
+#: ../extensions/deviceicon/battery.py:137
+#, fuzzy
+msgid "Removed"
+msgstr "Ondoa"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Inachaji"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Imebakiza nguvu (umeme) kidogo"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:(min).2d zimebaki"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Ina umeme"
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr "Tenganisha..."
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:264
+msgid "Connecting..."
+msgstr "Inaunganisha..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:270
+msgid "Connected"
+msgstr "Imeunganishwa"
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr "Mkondo "
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Spika zangyu"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Rudisha sauti"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Kata sauti"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Kundi"
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "mwanzo/kaya"
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Kazi"
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Ili kuweka mabadiliko yako inabidi kuanzisha upya sukari.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr "Tahadhari"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Mabadiliko yanahitaji kuanzisha upya"
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr "Ghairisha mabadiliko"
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Baadae"
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr "Anzisha sasa"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "Gotoka"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr "Ghairi"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr "Sawa"
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr "Thibitisha kufuta"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Thibitisha kufuta: Unataka ifutwe moja kwa moja %s?"
+
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Hifadhi"
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:407
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr "Futa"
+
+#: ../src/jarabe/desktop/activitieslist.py:428
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:432
+msgid "Make favorite"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr ""
+
+# unaweza kusema 'kujichanora' kwa maana ya 'up to date'
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Ifanye software iwe ya kisasa"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "Zifanye kazi zako kuwa za kisasa ilikusudi ziendane na software mpya"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Tafuta sasa"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Ona orodha"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Zinazoonwa sana"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr "Aina ya namba ya siri:"
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr "Unganisha"
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr "Tenganisha"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:466
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr "Endelea"
+
+#: ../src/jarabe/desktop/meshbox.py:471
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr "Ingia/unganisha"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "Haiwezi kuunganisha kwenye seva."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "Seva haiwezi kukamilisha ombi."
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52 ../src/jarabe/view/palettes.py:218
+msgid "Remove"
+msgstr "Ondoa"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "Fungua"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "Fungua kwa "
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s pogoa"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "Bofya kubadilisha rangi:"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Rejesha"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "Nyingine"
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Ondoa rafiki"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Kutana na rafiki"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Karibisha kwa %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr ""
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "Haiwezi kupata taarifa zinazohitajika kwa ajili ya usajiri."
+
+#~ msgid "Disconnecting..."
+#~ msgstr "Inatenganisha..."
+
+#~ msgid "Disconnected"
+#~ msgstr "Imetenganishwa"
+
+#~ msgid "About my XO"
+#~ msgstr "Kuhusu XO yangu"
diff --git a/shell/po/ta.po b/shell/po/ta.po
new file mode 100644
index 0000000..2851349
--- /dev/null
+++ b/shell/po/ta.po
@@ -0,0 +1,1260 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-26 00:31-0400\n"
+"PO-Revision-Date: 2009-08-28 04:52-0400\n"
+"Last-Translator: Emilianuspillai Amirthanathan Gnanaseelan "
+"<gnanaseelan2001@yahoo.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: ta\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 1.2.1\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "என்னைப் பற்றி"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "நீங்கள் பெயரை பதிவு செய்யுங்கள்."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "stroke: color=%s hue=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "stroke: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "நிரப்பு:........நிறம்=%s hue=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "நிரப்பு:.....%s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "குறித்த தவறை நிறத்தால் மாற்றியமைக்க."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "தவறை குறித்த நிறத்தால் நிறந்தீட்டுக."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr "பெயர்"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "நிறத்தை மாற்ற சொடுக்கு்"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr " என்னுடைய கணினியைப் பற்றி"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "கிடைக்கக்கூடிய வாய்ப்பில்லை."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "அடையாளம்"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "தொடர் இலக்கம்"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "மென்பொருள்"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "கட்டியெழுப்பு"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "சுகர்"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "கூட்டுப்பொருள்"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "இணைப்பில்லாத கூட்டுப்பொருள்"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "பிரதிசெய்து உறுதிப்படுத்து"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+" சுகர் என்பது பாவனையாளருக்கு பார்த்து தலையீடு செய்வ தற்கு சிறப்பாக "
+"அமைக்கப்பட்டுள்ளது.சுகர் இலவச மென்பொருளானதோடு,இது GNU பொது மக்கள் "
+"அனுமதியின்கீழ் கையாளப்படுகின்றதை மாற்றுவதற்கோ பிரதிகளை விநியோகிப்பதற்கோ "
+"குறித்த சில நிபந்தனைகளின்கீழ் இதனை மாற்றவோ இதன் பிரதிக ளை விநியோகிக்கவோ "
+"முடியும். "
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "முழு அனுமதி"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "திகதியும் நேரமும்"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "தவறு நேர வலையமைப்பு ஏற்கனவே இல்லை."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr "நேரவலயம்"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "சட்டகம்"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "பெறுமதி முழு எண்ணாக இருக்கவேண்டும்."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "ஒருபோதும்"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "உடனடியாக"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s செக்கன்கள்-"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "செயற்படுதல் தாமதம்"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "மூலை"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "விளிம்பு"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "மொழி"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "அடையவில்லை~/.i18n. தரமானவற்றை உருவாக்கு"
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "மொழி பரிபாஷை=%s முடிவுசெய்யவில்லை"
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr " மன்னிக்கவும் நான் பேசவில்லை"
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"உங்களது விருப்பத்திற்கு ஏற்றவாறு மொழிகளைச் சேர். ஏதாவது மொழிமாற்றம் "
+"கிடைக்காவிடில் அடுத்த பட்டியல் பாவிக்கப்படும்."
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "வலையமைப்பு"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "தரம் அறியப்படாதது"
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "குறித்த வானொலி விவாதம் தவறு.உபயோகியுங்கள்on/off."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "குறித்த வானொலி விவாதம் தவறு..உபயோகியுங்கள்0/1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "இணைப்பில்லாத"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "இணைப்பில்லாத வானொலியை நிறுத்தி மின்கலத்தை சேமி"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "வானொலி"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+"வ லையமைப்பு இணைக்கும்போது பிரச்சினைகள் இருப்பின் வலையமைப்பை துண்டித்து "
+"மீண்டும் வலையமைப்பை இணைக்க. "
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "வலையமைப்பை துண்டிக்கவும்"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "உதவி"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"வழங்கியானது (கணினி)நீங்கள் எந்த அறையில் உள்ளீர்கள் என்பதைக்காட்டுவதற்கு "
+"சமனானது:அதே வழங்கியிலுள்ள (கணினி)மக்களால் ஒவ்வொன்றையும் பார்க்க "
+"முடியும்,ஆனால் அவர்கள் ஒரே வலையமைப்பில் இல்லை."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "வழங்கி"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "வலு"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "தன்னியக்க pmவிவாதத்தில் தவறு. உபயோகிon/off."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "கடுமையான pm விவாதம் தவறு . உபயோகி on/off."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "வலு முகாமைத்துவம்"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "தன்னியக்க வலு முகாமைத்துவம் (மின் கலத்தின் வலுவைக் கூட்டுதல்)."
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"கடுமையான வலு முகாமைத்துவம் (கம்பித் தொடுகையற்ற கதிருக்கு மின்கலத்தின் மூலம் "
+"ஆயுளை கொடுத்தல்)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+#, fuzzy
+msgid "Software update"
+msgstr "மென் பொருளைப் புதுப்பித்தல்"
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+#, fuzzy
+msgid "None"
+msgstr "முடிந்து விட்டது"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "எனது மின்கலம்"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "அகற்று"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "மின்னேற்றல்"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "மிகச்சிறிய வலு எஞ்சியுள்ளது"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(மணித்தியாலம்)d:%(நிமி)).2dஎஞ்சியுள்ளது"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "மின்னேற்றம்"
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr "IP விலாசம்%s"
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr "இணைப்பை துண்டித்தல்"
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr "புதிய கம்பியில்லா வலையமைப்பை உருவாக்கு"
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:261
+msgid "Connecting..."
+msgstr "இணைத்தல்"
+
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:267
+msgid "Connected"
+msgstr "இணைக்கப்பட்டுள்ளது"
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr "தடம்"
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr "கம்பி வலையமைப்பு"
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr "வேகம்"
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr "% யின் வலையமைப்பு"
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "எனது ஒலி பெருக்கிகள்"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "ஒலியை ஆரம்பி"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "ஒலியை நிறுத்து"
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr "மெஷ்"
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "குழு"
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "வீடு"
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "செயற்பாடு"
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr "திரை வடிவம்"
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "\"%s\" யின் திரையின் படம்"
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr "URL ஊடாக மேலே செல்"
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+" நிறந்தீட்டிய XO வடிவத்தை திரைக்குப் பயன்பரடுத்தலாம்.நூலினை வடிவமைப்பதற்கு "
+"நிறத்தினையும் நிரப்பிய நிறத்தினையும்,rbg நிறக்கலவையினுாடாகப் "
+"பெற்றுக்கொள்ளலாம்."
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr " மூலை தாமதம்"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr "மூலையைப் பயன்படுத்துவதனால் சட்டகத்தின் செயற்பாடு தாமதம் அடைகின்றது"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+"ஒரத்தினைப் பயன் படுத்துவதனால் சட்டகச் செயற்பாட்டில் தாமதம் ஏற்படுகின்றது"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr "ஒரத்தின் தாமதம்"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr "விருப்பமான தளக்கோலம்"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr " விருப்பத்துக்குரியதை மீழ ஆரம்பி "
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"உண்மையாயின் Sugar எங்களை Jabberவழங்கி (கணினி)யின் ஊடக தேடல் நிலைக்கு இட்டுச் "
+"செல்லும்"
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "உண்மையாகில், Sugar \"வெளிச்செல்\" தேரிவைக் காட்டும். "
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr "Jabber வழங்கி (கணினி)"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr "விருப்பத்தித்குரிய செயற்பாட்டின் தளக்கோலதின் பார்வை"
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr "தன்னியக்க வலு "
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr "தன்னியக்க வலு"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr "கூடுதலான வலு"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr "கூடுதலான வலு"
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr "கருவிக்கு வெளிப்படுத்து"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr "ஒலித்திட்டமிடலை இல்லாமல் செய்வதற்கான செயற்பாடு"
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr "வெளிச் செல்கையைக் காட்டு"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr "ஒலியை நிறுத்து"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr "நேர வலையமைப்பை செயற்படுத்துவதற்கான அமைப்பு"
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr " jabber வழங்கி (கணினி)யிலுள்ள Url ஐ உபயோகி"
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr "Url எதனுள் சேமிக்கப்பட்டுள்ளது"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr "உபயோகிப்பவரின் நிறம்"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr "உபயோகிப்பவரின் பெயர்"
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr ""
+"திரையினுாடாக உட்செல்வதற்கு உபயோகிக்கும் பெயரைப் பயன்படுத்து "
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr "சத்தத்தின் அளவு"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr "ஒலிஉபகரணத்திற்கான சத்தத்தின் அளவு "
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"மீழ ஆரம்பிப்பதற்கு விரும்பிய icon மீது அழுத்தியவுடன் இறுதியாக செய்த "
+"செயற்பாடுகளைப் பெற்றுக் கொள்ளலாம்"
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar -கட்டுப்பாட்டு-பகுதி:எச்சரிக்கை அதே பெயருக்குரிய ஒன்றுக்கு மேற்பட்ட "
+"தெரிவுகளை தேடுதல்:%s மாற்றியமை %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "சுகர்-கட்டுப்பாட்டு-பட்டியல்:சாவி=%s கிடைக்கப்பெறாத தேர்வு"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "சுகர்-கட்டுப்பாட்டு-பட்டியல்:%s"
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"பயன்பாடு :சுகர்-கட்டுப்பாட்டு-பட்டியல்[ தேர்வு] சாவி[ args ... ] \n"
+"------சுகர் சூழலுக்கான கட்டுப்பாடு\n"
+"-----தேர்வு\n"
+"------h ------உதவிக்கான தகவலைப் பார்ப்பதுடன் வெளியாகு\n"
+"-------l-----பயன்படுத்தக் கூடிய தேர்வுகளைப் பட்டியல் இடு\n"
+"-------hசாவி----இந்த சாவிக்கான தகவலைக் காட்டு\n"
+"------g சாவி---- தற்போதைய சாவிக்கான பெறுமதியினைப் பெற்றுக்கொள்\n"
+"-----s சாவி------ தற்போதைய சாவிக்கான பெறுமதியினை ஒழுங்குபடுத்து \n"
+"------c சாவி----- தற்போதைய சாவிக்கான பெறுமதியினை நீக்கு\n"
+"------"
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "உங்களுடைய மாற்றங்களைப் பதிவதற்கு சுகரை மீள் ஆரம்பி\n"
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr "எச்சரிக்கை"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "மாற்றத்தினை மீள் ஆரம்பிப்பதற்கான கோரிக்கை"
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr "மாற்றத்தினை இரத்துசெய்"
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "பின்னர்"
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr "இப்போது மீள் ஆரம்பி"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr "முடிந்து விட்டது"
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr "இரத்துசெய்"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr "சரி"
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr "தலைப்பு"
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr "பதிப்பு"
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr "திகதி"
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr "பதிப்பு %கள்"
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr "அழிப்பதை உறுதி செய்"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "அழிப்பதை உறுதி செய்:உங்களுக்கு நிரந்தரமாக அழிக்க வேண்டுமா %s?"
+
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "வைத்திரு"
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:406
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr "அழி"
+
+#: ../src/jarabe/desktop/activitieslist.py:427
+msgid "Remove favorite"
+msgstr "விரும்பியதை அகற்று"
+
+#: ../src/jarabe/desktop/activitieslist.py:431
+msgid "Make favorite"
+msgstr "விரும்பியதை உருவாக்கு"
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "இலவச படிவம்"
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "வளையம்"
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:334
+msgid "Spiral"
+msgstr "சுருள்"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:401
+msgid "Box"
+msgstr "பெட்டி"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:442
+msgid "Triangle"
+msgstr "முக்கோணம்"
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr "பதிவுப்பிழை"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr "%கள்"
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr "பதிவு வெற்றிகரமானது"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr ""
+"நீங்கள் தற்போது உங்கள் பாடசாலையிலுள்ள வழங்கி (கணினி) யில் பதிவு "
+"செய்யப்பட்டுள்ளீர்"
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr "பதிவு"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "மென் பொருளைப் புதுப்பித்தல்"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "உங்கள் புதிய மென் பொருளுடன் செயற்பாடுகளை உறுதிப்படுத்துவதி புதுப்பி "
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "தற்போது பரிசீலி"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "பட்டியல் பார்வை"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "விருப்புக்குரிய பார்வை"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr "சாவி டைப்/வகை"
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr " நம்பத்தகுந்த டைப்/வகை"
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr "WPA & WPA2 தனிப்பட்ட"
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr "இணைப்பற்ற பாதுகாப்பு"
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr "இணை"
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr "இணைப்பை துண்டி"
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:463
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr "மீழ ஆரம்பி"
+
+#: ../src/jarabe/desktop/meshbox.py:468
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr "இணை"
+
+#: ../src/jarabe/desktop/schoolserver.py:34
+msgid "Cannot obtain data needed for registration."
+msgstr "உங்கள் பதிவிற்கு தேவையான தகவல்களைப் பெற்றுக்கொள்ள முடியாது"
+
+#: ../src/jarabe/desktop/schoolserver.py:51
+msgid "Cannot connect to the server."
+msgstr "வழங்கி (கணினி) யினை இணைக்க முடியாது"
+
+#: ../src/jarabe/desktop/schoolserver.py:56
+msgid "The server could not complete the request."
+msgstr "வழங்கி (கணினி) கட்டளையை முழுமையாக ஏற்கவில்லை"
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr "கோடு"
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr "%s of %s"
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr "%r ல்ருந்து மாற்று"
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr "ஏற்றுக்கொள்"
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr "இல்லாமல் செய்"
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr "%r ற்கு மாற்றம் செய்"
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr "அகற்று"
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr "திற"
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr "திறத்தலுடன்"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s சிறிதாக்குதல்"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "அயல்"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr "நிற மாற்றத்திற்காக அழுத்து"
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "பின்"
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr "அடுத்தது"
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr "பெயரிடப்படாத"
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr "பார்வை இன்மை"
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr "திகதியில்லை"
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr "பங்குபற்றுநர்"
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr "விளக்கம்"
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr "இணைக்கயிறு"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "சஞ்சிகை"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "தேடு"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "எந்நேரம்"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "இன்று"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "நேற்று வரை"
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "கடந்த வாரம்"
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "கடந்த மாதம்"
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "கடந்த வருடம்"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "யாராவது"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "எனது நண்பர்"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "எனது வகுப்பு"
+
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "ஏதாவது"
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr "பிரதி செய்"
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr "ஆரம்பி"
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr "உங்களுடைய சஞ்சிகை வெறுமையானது"
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr "பொருத்தமற்றப் பதிவுகள்"
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr "தேடலை நீக்கு"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "உங்கள் சஞ்சிகை நிரம்புயுள்ளது"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr " தயவு செய்து புதிய தகவல்களைப் பதிவதற்காக சில பழைய தகவல்களை அழிக்கவும்"
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "சஞ்சிகையைக் காட்டு"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "பொருளைத் தெரிவுசெய்"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "மூடு"
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr "மீழ ஆரம்பித்தலுடன்"
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr "ஆரம்பி"
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr "அனுப்பு"
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr "தகவல் பார்வை"
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr "தற்போது நண்பர்கள் இல்லை"
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr "அனுமதிக்கப்பட்ட இணைப்பு இடப்படவில்லை"
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr "மீழ ஆரம்பிப்பதற்கான செயற்பாடு இல்லை"
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr "ஆரம்பிப்பதற்கான செயற்பாடு இல்லை"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "நண்பணை அகற்று"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "நண்பணை உருவாக்கு"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "திரையை மூடுதல்"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "பதிவை அகற்று"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "எனது அமைப்பு"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "அழை %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "ஆரம்பி"
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr " வளப்(மூலம்)பார்வை"
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr "நிறுத்து"
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr "புதிதை ஆரம்பி"
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr "உள்ளடக்கியதைக் காட்டு "
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(மிகுதி_,இடம்)d MB மிகுதி"
+
+#: ../src/jarabe/view/palettes.py:218
+msgid "Unmount"
+msgstr "பதியாதே"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr " மாதிரி வளம் (மூலம்)"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr " வளம் (மூலம்)"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "செயற்பாட்டு வளத் (மூலம்) தொகுதி"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr " வளப் (மூலம்)பார்வை:%r"
+
+#~ msgid "Restart"
+#~ msgstr "மீள் ஆரம்பி"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008இல் ஒரு பிள்ளைக்கு ஒரு மடிமேல்கணினி கொடுக்க இணக்கம்Inc; Red Hat Inc; "
+#~ "andContributors."
diff --git a/shell/po/te.po b/shell/po/te.po
new file mode 100644
index 0000000..b52f7fe
--- /dev/null
+++ b/shell/po/te.po
@@ -0,0 +1,763 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-07-23 07:44-0400\n"
+"PO-Revision-Date: 2008-07-24 12:16-0400\n"
+"Last-Translator: Sayamindu Dasgupta <sayamindu@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65
+#: ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "పేరు"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "రంగు మార్చడానికి నొక్కు"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr "వెనుకకు"
+
+#: ../src/intro/intro.py:159
+#: ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "పూర్తి అయినది"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "తర్వాత"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "స్నేహం తీసివేయి"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "స్నేహం చేయి"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "%s కు పిలువు"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "తీసివేయి"
+
+#: ../src/view/clipboardmenu.py:53
+#: ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "తెరువు"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+#: ../src/view/home/HomeBox.py:86
+msgid "Keep"
+msgstr "ఉంచు"
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr "తో తెరువు"
+
+#: ../src/view/clipboardmenu.py:216
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "క్లిప్ బోర్డు వస్తువు : %s."
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "తాళం రకము:"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "దృడపరచుకొనే రకము:"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "గుప్త్తీకరించే రకము:"
+
+#: ../src/view/Shell.py:240
+msgid "Screenshot"
+msgstr "తెరముద్ర"
+
+#: ../src/view/home/HomeBox.py:80
+msgid "Confirm erase"
+msgstr "చెరిపివేయుట నిర్ద్దారణ చేయి"
+
+#: ../src/view/home/HomeBox.py:82
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "చెరిపివేయుట నిర్ద్దారణ చేయుట: %s శాశ్వతంగా చెరిపివేయబడుట ఇష్టమేనా?"
+
+#: ../src/view/home/HomeBox.py:89
+#: ../src/view/palettes.py:120
+msgid "Erase"
+msgstr "చెరిపివేయి"
+
+#: ../src/view/home/HomeBox.py:215
+msgid "List view"
+msgstr "వరసగా చూడు"
+
+#: ../src/view/home/HomeBox.py:216
+#, fuzzy
+msgid "<Ctrl>2"
+msgstr "<Ctrl>L"
+
+#: ../src/view/home/HomeBox.py:273
+msgid "Favorites view"
+msgstr "ఇష్టమైనవి చూచుటకు"
+
+#: ../src/view/home/HomeBox.py:274
+#, fuzzy
+msgid "<Ctrl>1"
+msgstr "<Ctrl>L"
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:282
+msgid "Freeform"
+msgstr "కలగలుపుగా"
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:289
+msgid "Ring"
+msgstr "వ్రుత్తము"
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "తగిలించు"
+
+#: ../src/view/home/MeshBox.py:106
+#, fuzzy
+msgid "Disconnect"
+msgstr "వేరుచేయబడింది"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:118
+#, fuzzy
+msgid "Disconnecting..."
+msgstr "వేరుచేయి . . ."
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:152
+#, fuzzy
+msgid "Connecting..."
+msgstr "వేరుచేయి . . ."
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr "తగిలించబడినది"
+
+#: ../src/view/home/MeshBox.py:211
+#: ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr "మెష్ వల"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:214
+#: ../src/view/devices/network/wireless.py:119
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr "వేరుచేయి . . ."
+
+#: ../src/view/home/MeshBox.py:302
+#: ../src/view/palettes.py:61
+msgid "Resume"
+msgstr "పునరారంభించు"
+
+#: ../src/view/home/MeshBox.py:307
+#: ../src/view/frame/activitiestray.py:205
+msgid "Join"
+msgstr "కలువు"
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr "నా బేటరీ"
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr "చార్జి అవుతుంది"
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr "చాలా తక్కువ చార్జీ మిగిలిఉంది"
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d మిగిలిఉంది"
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr "చార్జీ అయింది"
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr "నా స్పీకరులు"
+
+#: ../src/view/devices/speaker.py:119
+msgid "Unmute"
+msgstr "పలికించు"
+
+#: ../src/view/devices/speaker.py:122
+msgid "Mute"
+msgstr "నిశ్శబ్దంగా ఉంచు"
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr "వేరుచేయబడింది"
+
+#: ../src/view/devices/network/wireless.py:137
+msgid "Channel"
+msgstr "ప్రసారమార్గం"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "చుట్టుపక్కలవారు"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "గుంపు"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "ఇల్లు"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "వ్యాపకం"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"షుగర్-కంట్రోల్-పేనల్: గమనిక, అదేపేరుతో ఒకటికన్నా ఎక్కువ అవకాశాలు ఉన్నవి: %s "
+"module: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "షుగర్-కంట్రోల్-పేనల్: key=%s అవకాశం లేదు"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "షుగర్-కంట్రోల్-పేనల్: %s"
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr "షుగర్-కంట్రోల్-పేనల్:"
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "మీ మార్పులు పనిచేయడానికి సుగరును తిరిగి మొదలు పెట్టండి.\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "రద్దు చేయి"
+
+#: ../src/controlpanel/toolbar.py:121
+#: ../src/view/home/favoritesview.py:294
+msgid "Ok"
+msgstr "సరి"
+
+#: ../src/controlpanel/sectionview.py:34
+#: ../src/controlpanel/gui.py:260
+msgid "Changes require restart"
+msgstr "మార్పులు తిరిగి మొదలుపెట్తినతర్వాతే పనిచేస్తాయి"
+
+#: ../src/controlpanel/gui.py:259
+msgid "Warning"
+msgstr "గమనిక"
+
+#: ../src/controlpanel/gui.py:263
+msgid "Cancel changes"
+msgstr "మార్పులు రద్దుచేయి"
+
+#: ../src/controlpanel/gui.py:267
+msgid "Later"
+msgstr "తరవాత"
+
+#: ../src/controlpanel/gui.py:271
+msgid "Restart now"
+msgstr "ఇప్పుడు మరలామొదలుపెట్టు"
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr "మీరు పేరు నింపవలెను"
+
+#: ../src/controlpanel/model/aboutme.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "కుంచె: color=%s hue=%s"
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr "కుంచె: %s"
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "నింపు: color=%s hue=%s"
+
+#: ../src/controlpanel/model/aboutme.py:76
+#, python-format
+msgid "fill: %s"
+msgstr "నింపు: %s"
+
+#: ../src/controlpanel/model/aboutme.py:87
+msgid "Error in specified color modifiers."
+msgstr "నిర్ధేశించి చెప్పిన రంగులు మార్చడంలో పొరబాటు జరిగింది"
+
+#: ../src/controlpanel/model/aboutme.py:90
+msgid "Error in specified colors."
+msgstr "నిర్ధేశించి చెప్పిన రంగులలో పొరబాటు జరిగింది"
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "అలభ్యం"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr "పొరబాటు. కాలమండలమే లేదు."
+
+#: ../src/controlpanel/model/frame.py:38
+#: ../src/controlpanel/model/frame.py:60
+#, fuzzy
+msgid "Value must be an integer."
+msgstr "అంకెలు ఉపయోగించండి"
+
+#: ../src/controlpanel/model/language.py:28
+#, fuzzy
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "%s ప్రవేశము కుదరలేదు. ప్రమాణ మైన సెట్టింగ్ శ్రుష్తించనా."
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "కోడ్=%s కు భాష తెలియ లేదు."
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "మన్నించాలి నేను '%s'మాట్లాడలేను"
+
+#: ../src/controlpanel/model/network.py:48
+#, fuzzy
+msgid "You must enter a server."
+msgstr "మీరు పేరు నింపవలెను"
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr "ఉనికి తెలియదు"
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr "రేడియొ నిర్దేసించడంలో పొరబాటు. ఉంది/లేదు వాడనా ."
+
+#: ../src/controlpanel/model/power.py:57
+msgid "Error in automatic pm argument, use on/off."
+msgstr "దానంతట అదేజరిగే విద్యుత్తు నిర్వహణలో తప్పుజరింది, ఉంది/లేదు వాడు"
+
+#: ../src/controlpanel/model/power.py:86
+msgid "Error in extreme pm argument, use on/off."
+msgstr "అమోఘమైన విద్యుత్తు నిర్వహణలో తప్పుజరింది, ఉంది/లేదు వాడు"
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr "నాగురించి"
+
+#: ../src/controlpanel/view/aboutme.py:134
+#, fuzzy
+msgid "Click to change your color:"
+msgstr "రంగు మార్చడానికి నొక్కు"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr "నా ఎక్స్ ఒ గురించి"
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr "ఉనికి"
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr "వరుస సంఖ్య:"
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr "సాఫ్ట్​వేర్"
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr "బిల్డ్:"
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr "ఫర్మ్​వేర్:"
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr "తేదీ & కాలము"
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr "కాలమానం"
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr "ఫ్రేమ్"
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr "ఎప్పుడూకాదు"
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr "వెంటనే"
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr "%s సెకనులు"
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr "మొదలుపెట్టడంలో ఆలస్యమైంది"
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr "మూల"
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr "అంచు"
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr "భాష"
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr "వల"
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr "నిస్తం​త్రి"
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr "రేడియే"
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr "మెష్ వల "
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr "శెర్వరు:"
+
+#: ../src/controlpanel/view/power.py:27
+msgid "Power"
+msgstr "విద్యుత్తు "
+
+#: ../src/controlpanel/view/power.py:51
+msgid "Power management"
+msgstr "విద్యుత్తు నిర్వహణ"
+
+#: ../src/controlpanel/view/power.py:61
+msgid "Automatic power management (increases battery life)"
+msgstr "దానంతట అదే విద్యుత్తు నిర్వహణ(బేటరీ ఆయువు పెంచుతుంది)"
+
+#: ../src/controlpanel/view/power.py:89
+msgid ""
+"Extreme power management (disables wireless radio, increases battery life)"
+msgstr ""
+"అమోఘమైన విద్యుత్తు నిర్వహణ( నిస్తం​త్రిని ఆపుతుంది, బేటరీ ఆయువు పెంచుతుంది)"
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr "బడి మెష్ పొర్టల్ తో జతచేయబడింది"
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr "బడి మెష్ పొర్టల్ కోసమై చూస్తున్నా..."
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr "ఎక్స్ఒ మెష్ పొర్టల్ తో జతచేయబడింది"
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr "ఎక్స్ఒ మెష్ పొర్టల్ కోసమై చూస్తున్నా..."
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr "సరళమైన మెష్ తో జత కుదిరింది"
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr "సరళమైన మెష్ మొదలవుతుంది"
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr "తెలియని మెష్"
+
+#: ../src/view/frame/activitiestray.py:210
+msgid "Decline"
+msgstr "నిరస్కరించు"
+
+#: ../src/view/home/favoritesview.py:285
+msgid "Registration Failed"
+msgstr "రిజిస్టరుచేయడం విఫలమైంది"
+
+#: ../src/view/home/favoritesview.py:286
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/view/home/favoritesview.py:288
+msgid "Registration Successful"
+msgstr "రిజిస్టరుచేయడం విజయవంతమైంది"
+
+#: ../src/view/home/favoritesview.py:289
+msgid "You are now registered with your school server."
+msgstr "ఇప్పుడు మీరు బడి సెర్వరుతో రిజిస్టరుచేయబడిఉన్నారు"
+
+#: ../src/view/home/favoritesview.py:405
+msgid "Control Panel"
+msgstr "కంట్రొల్ పేనల్"
+
+#: ../src/view/home/favoritesview.py:416
+msgid "Restart"
+msgstr "తిరిగి మొదలుపెట్టు"
+
+#: ../src/view/home/favoritesview.py:421
+msgid "Shutdown"
+msgstr "ఫూర్తిగా ఆపు"
+
+#: ../src/view/home/favoritesview.py:427
+msgid "Register"
+msgstr "దాఖలు చేయి"
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr "మొదలవుతుంది..."
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr "ఆపు"
+
+#: ../src/view/palettes.py:104
+msgid "Start"
+msgstr "మొదలుపెట్టు"
+
+#: ../src/view/palettes.py:132
+msgid "Remove favorite"
+msgstr "ఇష్టమైనదానిని తొలగించు"
+
+#: ../src/view/palettes.py:136
+msgid "Make favorite"
+msgstr "ఇష్టమైనదానిగా తయారుచేయి"
+
+#: ../src/view/palettes.py:185
+msgid "Show contents"
+msgstr "విషయాలను చూపు"
+
+#: ../src/view/palettes.py:209
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB ఖాళీ"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "Ring view"
+#~ msgstr "ఉంగరంగా చూడు"
+
+#~ msgid "Add to ring"
+#~ msgstr "ఉంగరమునకు కలుపు"
+
+#~ msgid "off"
+#~ msgstr "లేదు"
+
+#~ msgid "on"
+#~ msgstr "ఉంది"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "అనుమతి లేదు. మీరు రూట్ గా మారి ప్రయత్నించాలి"
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "కాలమండలం చదవడంలో పొరబాటు జరిగింది"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "కాలమండలం నకలు చేయడంలో పొరబాటు జరిగింది (%s నుంచి ): %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "కాలమండలం అనుమతి మారుతుంది:%s"
+
+#~ msgid "About this XO"
+#~ msgstr "ఈ ఎక్స్ఒ గురించి"
+
+#~ msgid "Add to journal"
+#~ msgstr "పద్దుకి కలుపు"
+
+#~ msgid "Reboot"
+#~ msgstr "తిరిగి బూట్ చేయి"
+
+#~ msgid "My Battery life"
+#~ msgstr "నా బేటరీ ఆయువు"
+
+#~ msgid "Battery charging"
+#~ msgstr "బేటరీ చార్జి అవుతుంది"
+
+#~ msgid "Battery discharging"
+#~ msgstr "బేటరీ డిచ్చార్జి అవుతుంది"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "బేటరీ పుర్తిగా చార్జి అయింది"
+
+#~ msgid "Share with:"
+#~ msgstr "తో పంచుకో:"
+
+#~ msgid "Private"
+#~ msgstr "సొంతం"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "నా చుట్టుపక్కలవారు"
+
+#~ msgid "Undo"
+#~ msgstr "ఆఖరుది రద్దు చేయి"
+
+#~ msgid "Redo"
+#~ msgstr "తిరిగి చేయి"
+
+#~ msgid "Copy"
+#~ msgstr "నకలు"
+
+#~ msgid "Paste"
+#~ msgstr "అతికించు"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s వ్యాపకం"
+
+#~ msgid "Keep error"
+#~ msgstr "పొరబాటు జరిగింది"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "పొరబాటు జరిగింది : అన్ని మార్పులూ పోతాయి"
+
+#~ msgid "Don't stop"
+#~ msgstr "ఆపవద్దు"
+
+#~ msgid "Stop anyway"
+#~ msgstr "ఎలాగైనా ఆపువేయి"
+
+#~ msgid "Continue"
+#~ msgstr "కొనసాగించు"
+
+#~ msgid "OK"
+#~ msgstr "సరి"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d సంవత్సరము"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d సంవత్సరాలు"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d నెల"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d నెలలు"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d వారము"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d వారాలు"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d రోజు"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d రోజులు"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d గంట"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d గంటలు"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d నిమిషము"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d నిమిషాలు"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d సెకను"
+
+#~ msgid " and "
+#~ msgstr " మరియు "
+
+#, python-format
+#~ msgid ", "
+#~ msgstr ", "
diff --git a/shell/po/th.po b/shell/po/th.po
new file mode 100644
index 0000000..a79e711
--- /dev/null
+++ b/shell/po/th.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.0.1\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/tpi.po b/shell/po/tpi.po
new file mode 100644
index 0000000..e184567
--- /dev/null
+++ b/shell/po/tpi.po
@@ -0,0 +1,517 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-06-21 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:212
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/view/Shell.py:262
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:147
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:148
+msgid "<Ctrl>L"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:204
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:205
+msgid "<Ctrl>R"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:211
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:218
+msgid "Ring"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:38
+#: ../src/view/devices/network/mesh.py:65
+#: ../src/view/devices/network/mesh.py:69
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:116
+#: ../src/view/devices/network/mesh.py:86
+msgid "Disconnect..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:60
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:219
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:42
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:111
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:120
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:124
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:40
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:104
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:107
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:64
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:134
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:250
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:249
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:253
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:257
+msgid "Later"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:261
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:67
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:70
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:85
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutme.py:88
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:108
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:110
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:115
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:120
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:127
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:224
+msgid "Decline"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:351
+msgid "Control Panel"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:362
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:367
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:373
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:41
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:71
+msgid "Stop"
+msgstr ""
+
+#: ../src/view/palettes.py:96
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:119
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:123
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:169
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:193
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
diff --git a/shell/po/tr.po b/shell/po/tr.po
new file mode 100644
index 0000000..696a3c0
--- /dev/null
+++ b/shell/po/tr.po
@@ -0,0 +1,839 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-25 00:30-0400\n"
+"PO-Revision-Date: 2008-09-26 09:38-0400\n"
+"Last-Translator: abdullah kocabas <abdullah.kocabas@abcdizustu.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/window.py:93 ../src/controlpanel/aboutme/view.py:100
+msgid "Name:"
+msgstr "İsim:"
+
+#: ../src/intro/window.py:125
+msgid "Click to change color:"
+msgstr "Renk değiştirmek için tıkla:"
+
+#: ../src/intro/window.py:175 ../src/journal/detailview.py:119
+msgid "Back"
+msgstr "Geri"
+
+#: ../src/intro/window.py:189 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "Kapat"
+
+#: ../src/intro/window.py:192
+msgid "Next"
+msgstr "İleri"
+
+#: ../src/view/BuddyMenu.py:60
+msgid "Remove friend"
+msgstr "Arkadaşı Kaldır"
+
+#: ../src/view/BuddyMenu.py:63
+msgid "Make friend"
+msgstr "Arkadaş Ekle"
+
+#: ../src/view/BuddyMenu.py:92
+#, python-format
+msgid "Invite to %s"
+msgstr "Davet et %s"
+
+#: ../src/view/clipboardmenu.py:51
+msgid "Remove"
+msgstr "Kaldır"
+
+#: ../src/view/clipboardmenu.py:56 ../src/view/clipboardmenu.py:78
+msgid "Open"
+msgstr "Aç"
+
+#: ../src/view/clipboardmenu.py:61 ../src/view/home/HomeBox.py:84
+msgid "Keep"
+msgstr "Kaydet"
+
+#: ../src/view/clipboardmenu.py:83
+msgid "Open with"
+msgstr "Birlikte Aç"
+
+#: ../src/view/clipboardmenu.py:228
+#, python-format
+msgid "%s clipping"
+msgstr "%s Kırp"
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "Tuş Çeşidi:"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "Kimlik Denetleme Çeşidi:"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "Şifreleme Çeşidi:"
+
+#: ../src/hardware/schoolserver.py:17
+msgid "Cannot obtain data needed for registration."
+msgstr "Kayıt İçin Gerekli Bilgileri Sağlayamıyor"
+
+#: ../src/hardware/schoolserver.py:31
+msgid "Cannot connect to the server."
+msgstr "Sunucuya Bağlanamıyor"
+
+#: ../src/hardware/schoolserver.py:36
+msgid "The server could not complete the request."
+msgstr "Sunucu İsteği Tamamlayamıyor"
+
+#: ../src/view/Shell.py:251
+msgid "Screenshot"
+msgstr "Ekran Resmi"
+
+#: ../src/view/home/HomeBox.py:78
+msgid "Confirm erase"
+msgstr "Silmeyi Onayla"
+
+#: ../src/view/home/HomeBox.py:80
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Silme Onayı: %s i tamamen silmek mi istiyorsunuz?"
+
+#: ../src/view/home/HomeBox.py:87 ../src/view/palettes.py:120
+#: ../src/journal/journaltoolbox.py:335 ../src/journal/palettes.py:75
+msgid "Erase"
+msgstr "Silme"
+
+#: ../src/view/home/HomeBox.py:117
+msgid "Software Update"
+msgstr "Yazılım Güncelleme"
+
+#: ../src/view/home/HomeBox.py:118
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "Aktivitelerinizi yeni yazılıma uygun hale getirmek için güncelleyiniz"
+
+#: ../src/view/home/HomeBox.py:122 ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "İptal"
+
+#: ../src/view/home/HomeBox.py:124 ../src/controlpanel/gui.py:273
+msgid "Later"
+msgstr "Daha Sonra"
+
+#: ../src/view/home/HomeBox.py:127
+msgid "Check now"
+msgstr "Şimdi Kontrol Et"
+
+#: ../src/view/home/HomeBox.py:261
+msgid "List view"
+msgstr "Liste Görünümü"
+
+#: ../src/view/home/HomeBox.py:262
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/view/home/HomeBox.py:320
+msgid "Favorites view"
+msgstr "Favoriler Görünümü"
+
+#: ../src/view/home/HomeBox.py:321
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "Bağlan"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "Bağlantıyı kes"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "Bağlantı kesiliyor..."
+
+#: ../src/view/home/MeshBox.py:159
+msgid "Connecting..."
+msgstr "Bağlanıyor..."
+
+# TODO: show the channel number
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:166
+msgid "Connected"
+msgstr "Bağlı"
+
+#: ../src/view/home/MeshBox.py:218 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr "Mesh Ağı"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:221 ../src/view/devices/network/wireless.py:125
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr "Bağlantıyı kes..."
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/view/home/MeshBox.py:309 ../src/view/palettes.py:61
+#: ../src/journal/journaltoolbox.py:399 ../src/journal/palettes.py:57
+msgid "Resume"
+msgstr "Devam Et"
+
+#: ../src/view/home/MeshBox.py:314 ../src/view/frame/activitiestray.py:206
+msgid "Join"
+msgstr "Katıl"
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr "Pil Durumu"
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr "Şarj"
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr "Çok az şarj kaldı"
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d kaldı"
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr "Şarj edildi"
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr "Hoparlör"
+
+#: ../src/view/devices/speaker.py:125
+msgid "Unmute"
+msgstr "Sesi açık"
+
+#: ../src/view/devices/speaker.py:128
+msgid "Mute"
+msgstr "Sessiz"
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr "Bağlantı kesildi"
+
+#: ../src/view/devices/network/wireless.py:143
+msgid "Channel"
+msgstr "Kanal"
+
+#: ../src/view/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Komşular"
+
+#: ../src/view/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Grup"
+
+#: ../src/view/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Ana ekran"
+
+#: ../src/view/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Aktivite"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-kontrol-paneli: UYARI, aynı isimle birden fazla seçenek buldu: %s "
+"birim: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-kontrol-panel: anahtar=%s geçerli bir seçenek değil"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-kontrol-panel: %s"
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/controlpanel/cmd.py:35
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Kullanım: sugar-kontrol-paneli [ seçenek ] anahtar [ args ... ] \n"
+"Sugar ortamı için kontrol \n"
+"Seçenekler:\n"
+"-h Bu yardım mesajını göster ve çık \n"
+"-l Tüm uygun seçenekleri listele \n"
+"-h anahtarı Bu anahtar hakkındaki bilgileri göster \n"
+"-g anahtarı Bu anahtarın son değerini al \n"
+"-s anahtarı Bu anahtarın son değerini kur \n"
+"\t"
+
+#: ../src/controlpanel/cmd.py:48
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Değişikliklerinizin etkinleşmesi için bilgisayarı tekrar başlatmanız "
+"gerekiyor\n"
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:305
+msgid "Ok"
+msgstr "Tamam"
+
+#: ../src/controlpanel/sectionview.py:42 ../src/controlpanel/gui.py:265
+msgid "Changes require restart"
+msgstr "Değişiklikler bilgisayarın tekrar başlatılmasını gerektiriyor"
+
+#: ../src/controlpanel/gui.py:264
+msgid "Warning"
+msgstr "Uyarı"
+
+#: ../src/controlpanel/gui.py:268
+msgid "Cancel changes"
+msgstr "Değişiklikleri İptal Et"
+
+#: ../src/controlpanel/gui.py:277
+msgid "Restart now"
+msgstr "Şimdi Tekrar Başlat"
+
+#: ../src/controlpanel/aboutme/model.py:44
+msgid "You must enter a name."
+msgstr "Bir isim girmeniz gerekiyor"
+
+#: ../src/controlpanel/aboutme/model.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "fırça darbesi:_ renk=%s renk=%s"
+
+#: ../src/controlpanel/aboutme/model.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr "fırça darbesi:_ %s"
+
+#: ../src/controlpanel/aboutme/model.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "doldurma:_ renk=%s renk=%s"
+
+#: ../src/controlpanel/aboutme/model.py:76
+#, python-format
+msgid "fill: %s"
+msgstr "doldurma:_ %s"
+
+#: ../src/controlpanel/aboutme/model.py:87
+msgid "Error in specified color modifiers."
+msgstr "Belirtilen renk değiştiricilerinde hata"
+
+#: ../src/controlpanel/aboutme/model.py:90
+msgid "Error in specified colors."
+msgstr "Belirtilen renklerde hata"
+
+#: ../src/controlpanel/aboutme/view.py:32
+#: ../src/controlpanel/aboutme/__init__.py:22
+msgid "About Me"
+msgstr "Benim Hakkımda"
+
+#: ../src/controlpanel/aboutme/view.py:134
+msgid "Click to change your color:"
+msgstr "Renk değiştirmek için tıklayınız:"
+
+#: ../src/controlpanel/aboutxo/model.py:24
+msgid "Not available"
+msgstr "Mevcut değil"
+
+#: ../src/controlpanel/aboutxo/view.py:55
+msgid "Identity"
+msgstr "Kimlik"
+
+#: ../src/controlpanel/aboutxo/view.py:64
+msgid "Serial Number:"
+msgstr "Seri Numarası:"
+
+#: ../src/controlpanel/aboutxo/view.py:87
+msgid "Software"
+msgstr "Yazılım"
+
+#: ../src/controlpanel/aboutxo/view.py:96
+msgid "Build:"
+msgstr "Yapı:"
+
+#: ../src/controlpanel/aboutxo/view.py:111
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../src/controlpanel/aboutxo/view.py:126
+msgid "Firmware:"
+msgstr "Aygıt Yazılımı:"
+
+#: ../src/controlpanel/aboutxo/view.py:148
+msgid "Copyright and License"
+msgstr "Telif Hakkı ve Lisans"
+
+#: ../src/controlpanel/aboutxo/view.py:156
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; ve Destekçiler"
+
+#: ../src/controlpanel/aboutxo/view.py:163
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Sugar gördüğünüz grafiksel kullanıcı arayüzüdür. Sugar, GNU General Public "
+"Lisansı'na sahip, ücretsiz bir yazılımdır. İstediğiniz takdirde yazılımı "
+"değiştirebilir ve/veya burada açıklanan belli koşullar altında kopyasını "
+"dağıtabilirsiniz."
+
+#: ../src/controlpanel/aboutxo/view.py:175
+msgid "Full license:"
+msgstr "Tam Lisans:"
+
+#: ../src/controlpanel/aboutxo/__init__.py:21
+msgid "About my XO"
+msgstr "XO Bilgisayarım Hakkında"
+
+#: ../src/controlpanel/datetime/model.py:89
+msgid "Error timezone does not exist."
+msgstr "Hatalı zaman dilimi yok"
+
+#: ../src/controlpanel/datetime/view.py:68
+msgid "Timezone"
+msgstr "Saat Dilimi"
+
+#: ../src/controlpanel/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Tarih ve Zaman"
+
+#: ../src/controlpanel/frame/model.py:38 ../src/controlpanel/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Değer bir tamsayı olmalı"
+
+#: ../src/controlpanel/frame/view.py:26
+msgid "never"
+msgstr "asla"
+
+#: ../src/controlpanel/frame/view.py:27
+msgid "instantaneous"
+msgstr "anlık"
+
+#: ../src/controlpanel/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s saniyeler"
+
+#: ../src/controlpanel/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Aktivasyon Gecikmesi"
+
+#: ../src/controlpanel/frame/view.py:76
+msgid "Corner"
+msgstr "Köşe"
+
+#: ../src/controlpanel/frame/view.py:111
+msgid "Edge"
+msgstr "Kenar"
+
+#: ../src/controlpanel/frame/__init__.py:21
+msgid "Frame"
+msgstr "Çerçeve"
+
+#: ../src/controlpanel/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "~/.i18n e girilemiyor. Standart ayarları oluşturunuz"
+
+#: ../src/controlpanel/language/model.py:114
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "kod=%s için dil tanımlanamadı"
+
+#: ../src/controlpanel/language/model.py:131
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Üzgünüm, %s konuşmuyorum"
+
+#: ../src/controlpanel/language/view.py:70
+#: ../src/controlpanel/language/__init__.py:21
+msgid "Language"
+msgstr "Dil"
+
+#: ../src/controlpanel/network/model.py:62
+msgid "State is unknown."
+msgstr "Durum bilinmiyor"
+
+#: ../src/controlpanel/network/model.py:82
+msgid "Error in specified radio argument use on/off."
+msgstr "Belirtilen bağlantı noktasında hata vardır, açma kapama yapınız"
+
+#: ../src/controlpanel/network/view.py:28
+#: ../src/controlpanel/network/__init__.py:21
+msgid "Network"
+msgstr "Ağ"
+
+#: ../src/controlpanel/network/view.py:54
+msgid "Wireless"
+msgstr "Kablosuz Bağlantı"
+
+#: ../src/controlpanel/network/view.py:62
+msgid "Turn of the wireless radio to save battery life"
+msgstr "Pil ömrünü arttırmak için kablosuz bağlantı özelliğini kapatınız."
+
+#: ../src/controlpanel/network/view.py:75
+msgid "Radio"
+msgstr "Bağlantı "
+
+#: ../src/controlpanel/network/view.py:91
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "Ağa bağlanmada sorun yaşıyorsanız ağ geçmişini silebilirsiniz."
+
+#: ../src/controlpanel/network/view.py:100
+msgid "Discard network history"
+msgstr "Ağ geçmişini siliniz."
+
+#: ../src/controlpanel/network/view.py:113
+msgid "Mesh"
+msgstr "Mesh"
+
+#: ../src/controlpanel/network/view.py:122
+msgid "Server:"
+msgstr "Sunucu:"
+
+#: ../src/controlpanel/power/model.py:55
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Otomatik pm değişkeninde hata vardır, açma kapama yapınız"
+
+#: ../src/controlpanel/power/model.py:84
+msgid "Error in extreme pm argument, use on/off."
+msgstr "En uçtaki pm değişkeninde hata vardır, açma kapama yapınız"
+
+#: ../src/controlpanel/power/view.py:47
+msgid "Power management"
+msgstr "Güç Kontrolü"
+
+#: ../src/controlpanel/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Otomatik güç kontrolü (pil ömrünü uzatır)"
+
+#: ../src/controlpanel/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Aşırı güç kontrolü (kablosuz bağlantı özelliğini etkisiz kılar, şarj ömrünü "
+"uzatır)"
+
+#: ../src/controlpanel/power/__init__.py:21
+msgid "Power"
+msgstr "Güç"
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr "Okul Mesh Ağı Portalı'na bağlandı."
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr "Okul Mesh Ağı Portalı arıyor..."
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr "XO Mesh Ağı Portalı'na bağlandı."
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr "XO Mesh Ağ Portalı arıyor..."
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr "Sadece Mesh Ağına bağlandı."
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr "Sadece Mesh Ağı başlatıyor."
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr "Bilinmeyen Mesh Ağı"
+
+#: ../src/view/frame/activitiestray.py:211
+msgid "Decline"
+msgstr "Azalmak"
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:107
+msgid "Freeform"
+msgstr "dağınık görünüm"
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:189
+msgid "Ring"
+msgstr "çember görünümü"
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:334
+msgid "Spiral"
+msgstr "sarmal"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:401
+msgid "Box"
+msgstr "kutu"
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:442
+msgid "Triangle"
+msgstr "üçgen"
+
+#: ../src/view/home/favoritesview.py:295
+msgid "Registration Failed"
+msgstr "Kayıt Başarısız"
+
+#: ../src/view/home/favoritesview.py:296
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/view/home/favoritesview.py:298
+msgid "Registration Successful"
+msgstr "Kayıt Başarılı"
+
+#: ../src/view/home/favoritesview.py:299
+msgid "You are now registered with your school server."
+msgstr "Şu an okul sunucunuza kayıt oldunuz"
+
+#: ../src/view/home/favoritesview.py:420
+msgid "Settings"
+msgstr "Ayarlar"
+
+#: ../src/view/home/favoritesview.py:425
+msgid "Restart"
+msgstr "Yeniden Başlat"
+
+#: ../src/view/home/favoritesview.py:430
+msgid "Shutdown"
+msgstr "Kapat"
+
+#: ../src/view/home/favoritesview.py:436
+msgid "Register"
+msgstr "Kaydol"
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr "Başlıyor..."
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr "Durdur"
+
+#. TRANS: Action label for starting an entry.
+#: ../src/view/palettes.py:104 ../src/journal/journaltoolbox.py:402
+#: ../src/journal/palettes.py:59
+msgid "Start"
+msgstr "Başlat"
+
+#: ../src/view/palettes.py:138
+msgid "Remove favorite"
+msgstr "Favorilerimden kaldır"
+
+#: ../src/view/palettes.py:142
+msgid "Make favorite"
+msgstr "Favorilerime ekle"
+
+#: ../src/view/palettes.py:191
+msgid "Show contents"
+msgstr "İçeriklerini göster"
+
+#: ../src/view/palettes.py:215
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB boş"
+
+#: ../src/journal/journaltoolbox.py:62
+msgid "Search"
+msgstr "Arama"
+
+#: ../src/journal/journaltoolbox.py:119
+msgid "Anytime"
+msgstr "Herhangi bir zaman"
+
+#: ../src/journal/journaltoolbox.py:121
+msgid "Today"
+msgstr "Bugün"
+
+#: ../src/journal/journaltoolbox.py:123
+msgid "Since yesterday"
+msgstr "Dünden itibaren"
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/journal/journaltoolbox.py:125
+msgid "Past week"
+msgstr "Geçen hafta"
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/journal/journaltoolbox.py:127
+msgid "Past month"
+msgstr "Geçen ay"
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/journal/journaltoolbox.py:129
+msgid "Past year"
+msgstr "Geçen yıl"
+
+#: ../src/journal/journaltoolbox.py:136
+msgid "Anyone"
+msgstr "Herhangi biri"
+
+#: ../src/journal/journaltoolbox.py:138
+msgid "My friends"
+msgstr "Arkadaşlarım"
+
+#: ../src/journal/journaltoolbox.py:139
+msgid "My class"
+msgstr "Sınıfım"
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/journal/journaltoolbox.py:255
+msgid "Anything"
+msgstr "Herhangi bir şey"
+
+#. TODO: Add "Start with" menu item
+#: ../src/journal/journaltoolbox.py:325 ../src/journal/palettes.py:67
+msgid "Copy"
+msgstr "Kopyala"
+
+#: ../src/journal/collapsedentry.py:248 ../src/journal/expandedentry.py:176
+#: ../src/journal/palettes.py:51
+msgid "Untitled"
+msgstr "İsimsiz"
+
+#: ../src/journal/journalactivity.py:119 ../src/journal/volumesmanager.py:57
+msgid "Journal"
+msgstr "Günlük"
+
+#: ../src/journal/expandedentry.py:222
+msgid "No preview"
+msgstr "Ön izleme yok"
+
+#: ../src/journal/expandedentry.py:241
+msgid "Participants:"
+msgstr "Katılımcılar:"
+
+#: ../src/journal/expandedentry.py:266
+msgid "Description:"
+msgstr "Tanım:"
+
+#: ../src/journal/expandedentry.py:292
+msgid "Tags:"
+msgstr "Etiketler:"
+
+#: ../src/journal/objectchooser.py:134
+msgid "Choose an object"
+msgstr "Bir nesne seçiniz"
+
+#: ../src/journal/objectchooser.py:139
+msgid "Close"
+msgstr "Kapat"
+
+#: ../src/journal/volumestoolbar.py:93
+msgid "Unmount"
+msgstr "Bağlantıyı kaldır"
+
+#: ../src/journal/misc.py:95
+msgid "No date"
+msgstr "Tarih yok"
+
+#: ../src/journal/listview.py:39
+msgid "Your Journal is empty"
+msgstr "Günlüğünüz boş"
+
+#: ../src/journal/listview.py:40
+msgid "No matching entries "
+msgstr "Eşleşen bir giriş yok_"
+
+#: ../src/journal/modalalert.py:59
+msgid "Your Journal is full"
+msgstr "Günlüğünüz dolu"
+
+#: ../src/journal/modalalert.py:63
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"Yeni girişler yapabilmek için lütfen günlükteki eski kayıtlardan bir kısmını "
+"siliniz"
+
+#: ../src/journal/modalalert.py:75
+msgid "Show Journal"
+msgstr "Günlüğü göster"
+
+#~ msgid "Add to journal"
+#~ msgstr "Günlüğe ekleyiniz."
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Pano nesnesi: %s"
+
+#~ msgid "Reboot"
+#~ msgstr "Yeniden başlatınız."
+
+#~ msgid "About this XO"
+#~ msgstr "Bu XO hakkında"
+
+#~ msgid "My Battery life"
+#~ msgstr "Pil ömrüm"
+
+#~ msgid "Battery charging"
+#~ msgstr "Pil doluyor."
+
+#~ msgid "Battery discharging"
+#~ msgstr "Pil boşalıyor."
+
+#~ msgid "Battery fully charged"
+#~ msgstr "Pil tam dolu"
+
+#~ msgid "off"
+#~ msgstr "kapalı"
+
+#~ msgid "on"
+#~ msgstr "açık"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr ""
+#~ "İzin reddedildi. Bu metodu çalıştırmak için merkezden olmanız gerekmektedir."
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "Saat diliminde hata vardır."
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "Saat dilimini %s'ten kopyalarken hata oluşmuştur: %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "Saat dilimini değiştirme izni: %s"
diff --git a/shell/po/tvl.po b/shell/po/tvl.po
new file mode 100644
index 0000000..eccea53
--- /dev/null
+++ b/shell/po/tvl.po
@@ -0,0 +1,1188 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-09-16 00:31-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.3.0\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+msgid "None"
+msgstr ""
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:264
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:270
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:334
+msgid "Ok"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:329
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:673
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:466
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:471
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:245
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:264
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:265
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:266
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:288 ../src/jarabe/journal/misc.py:89
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:295
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:318
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:343
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:352
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:354
+msgid "No matching entries"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:365
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr ""
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr ""
diff --git a/shell/po/tzo.po b/shell/po/tzo.po
new file mode 100644
index 0000000..afc8693
--- /dev/null
+++ b/shell/po/tzo.po
@@ -0,0 +1,1210 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-26 00:31-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.3.0\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:27
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:187
+msgid "Keyboard Model"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:243
+msgid "Key(s) to change layout"
+msgstr ""
+
+#: ../extensions/cpsection/keyboard/view.py:311
+msgid "Keyboard Layout(s)"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:62
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:122
+#, python-format
+msgid "Checking %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:124
+#, python-format
+msgid "Downloading %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:126
+#, python-format
+msgid "Updating %s..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:135
+msgid "Your software is up-to-date"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:137
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:155
+msgid "Checking for updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:160
+msgid "Installing updates..."
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:165
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: ../extensions/cpsection/updater/view.py:244
+msgid "Install selected"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:265
+#, python-format
+msgid "Download size: %s"
+msgstr ""
+
+#: ../extensions/cpsection/updater/view.py:353
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr ""
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:373
+msgid "None"
+msgstr ""
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:376
+msgid "1 KB"
+msgstr ""
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:379
+#, python-format
+msgid "%.0f KB"
+msgstr ""
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:382
+#, python-format
+msgid "%.1f MB"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:44
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:110
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:114
+msgid "Create new wireless network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:120
+#: ../src/jarabe/desktop/meshbox.py:261
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:124
+#: ../extensions/deviceicon/network.py:186
+#: ../src/jarabe/desktop/meshbox.py:267
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:146
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:161
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:189
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:415
+#, python-format
+msgid "%s's network %s"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:56
+msgid "Mesh"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:58
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:60
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:66
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:69
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:71
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Keyboard layouts"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Keyboard model"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Keyboard options"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "List of keyboard options."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Show Log out"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "The keyboard model to be used"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:31
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:32
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:33
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:36
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:280
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:284
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:289 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:293
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:726
+#: ../src/jarabe/frame/activitiestray.py:822
+#: ../src/jarabe/frame/activitiestray.py:850
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:332
+msgid "Ok"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:80
+#: ../src/jarabe/journal/listview.py:147
+msgid "Title"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:91
+msgid "Version"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:105
+#: ../src/jarabe/journal/listview.py:178
+msgid "Date"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:234
+#, python-format
+msgid "Version %s"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:355
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:361
+#: ../src/jarabe/frame/clipboardmenu.py:62
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:364
+#: ../src/jarabe/desktop/activitieslist.py:406
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:112
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:427
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/desktop/activitieslist.py:431
+msgid "Make favorite"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:401
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:442
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:323
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:671
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:136
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:140
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:463
+#: ../src/jarabe/frame/activitiestray.py:761
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:72 ../src/jarabe/view/palettes.py:64
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:468
+#: ../src/jarabe/frame/activitiestray.py:235
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:34
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:51
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:56
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:240
+#: ../src/jarabe/frame/activitiestray.py:698
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:652
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:654
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:671
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:683
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:693
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:716
+#: ../src/jarabe/frame/activitiestray.py:840
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:750
+#: ../src/jarabe/frame/activitiestray.py:875
+msgid "Dismiss"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:810
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:164
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:210
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+#, python-format
+msgid "Kind: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:229
+msgid "Unknown"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:230
+#, python-format
+msgid "Date: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:231
+#, python-format
+msgid "Size: %s"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:253 ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:260
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:283
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:309
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:90
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:75
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:361
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:363
+msgid "No matching entries"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:374
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:73
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:76
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:98
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:107
+msgid "View Details"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:185
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:190
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:218
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:220
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr ""
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:71
+msgid "View Source"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:82
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:122
+msgid "Start new"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:171
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:193 ../src/jarabe/view/palettes.py:243
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:218
+msgid "Unmount"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr ""
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr ""
diff --git a/shell/po/ug.po b/shell/po/ug.po
new file mode 100644
index 0000000..a45bff2
--- /dev/null
+++ b/shell/po/ug.po
@@ -0,0 +1,979 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-01-27 13:34-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:92
+msgid "Name:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/model.py:26
+msgid "Not available"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:59
+msgid "Identity"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:68
+msgid "Serial Number:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:90
+msgid "Software"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:99
+msgid "Build:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:114
+msgid "Sugar:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:130
+msgid "Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:145
+msgid "Wireless Firmware:"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:168
+msgid "Copyright and License"
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:176
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:183
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../extensions/cpsection/aboutcomputer/view.py:195
+msgid "Full license:"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:19
+msgid "Timezone"
+msgstr ""
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:32
+msgid "Language"
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:56
+msgid "Wireless"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:64
+msgid "Turn off the wireless radio to save battery life"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:77
+msgid "Radio"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:93
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:102
+msgid "Discard network history"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:115
+msgid "Collaboration"
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:123
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+
+#: ../extensions/cpsection/network/view.py:133
+msgid "Server:"
+msgstr ""
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:56
+msgid "My Battery"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../extensions/deviceicon/battery.py:153
+msgid "Charged"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:40
+#, python-format
+msgid "IP address: %s"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:104
+msgid "Disconnect..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:109
+#: ../src/jarabe/desktop/meshbox.py:246
+msgid "Connecting..."
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:113
+#: ../extensions/deviceicon/network.py:166
+#: ../src/jarabe/desktop/meshbox.py:252
+msgid "Connected"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:126
+msgid "Channel"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:141
+msgid "Wired Network"
+msgstr ""
+
+#: ../extensions/deviceicon/network.py:169
+msgid "Speed"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:46
+msgid "My Speakers"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:128
+msgid "Unmute"
+msgstr ""
+
+#: ../extensions/deviceicon/speaker.py:131
+msgid "Mute"
+msgstr ""
+
+#: ../extensions/globalkey/screenshot.py:50
+msgid "Screenshot"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:196
+#, python-format
+msgid "View source: %r"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:205
+#: ../src/jarabe/frame/zoomtoolbar.py:42
+msgid "Activity"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:212
+msgid "Document"
+msgstr ""
+
+#: ../extensions/globalkey/viewsource.py:226
+#: ../src/jarabe/journal/objectchooser.py:141
+msgid "Close"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:1
+msgid "Backup URL"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:2
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:3
+msgid "Corner Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Delay for the activation of the frame using the corners."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Delay for the activation of the frame using the edges."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Edge Delay"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Favorites Layout"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Favorites resume mode"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:9
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Jabber Server"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Layout of the favorites view."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Power Automatic"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Power Automatic."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Power Extreme"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:15
+msgid "Power Extreme."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:16
+msgid "Publish to Gadget"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Setting for muting the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Sound Muted"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Timezone setting for the system."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Url of the jabber server to use."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:22
+msgid "Url where the backup is saved to."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:23
+msgid "User Color"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:24
+msgid "User Name"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:25
+msgid "User name that is used throughout the desktop."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Volume Level"
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Volume level for the sound device."
+msgstr ""
+
+#: ../data/sugar.schemas.in.h:28
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:272
+msgid "Warning"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:273
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:276
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:281 ../src/jarabe/desktop/homebox.py:113
+msgid "Later"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Restart now"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:188
+msgid "Done"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:111
+#: ../src/jarabe/frame/activitiestray.py:683
+#: ../src/jarabe/frame/activitiestray.py:762
+#: ../src/jarabe/frame/activitiestray.py:790
+msgid "Cancel"
+msgstr ""
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:334
+msgid "Ok"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:114
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:196
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:341
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:408
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:449
+msgid "Triangle"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:326
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:329
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/jarabe/desktop/favoritesview.py:666
+msgid "Register"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:67
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:69
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:73 ../src/jarabe/frame/clipboardmenu.py:62
+msgid "Keep"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:76
+#: ../src/jarabe/journal/journaltoolbox.py:357
+#: ../src/jarabe/journal/palettes.py:97 ../src/jarabe/view/palettes.py:127
+msgid "Erase"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:106
+msgid "Software Update"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:107
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:116
+msgid "Check now"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:233
+msgid "List view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:234
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:296
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:297
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/jarabe/desktop/homebox.py:304
+msgid "Resume by default"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:131
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:151
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:215
+msgid "WPA & WPA2 Personal"
+msgstr ""
+
+#: ../src/jarabe/desktop/keydialog.py:224
+msgid "Wireless Security:"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:130
+msgid "Connect"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:134
+msgid "Disconnect"
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:440
+#: ../src/jarabe/frame/activitiestray.py:707
+#: ../src/jarabe/journal/journaltoolbox.py:425
+#: ../src/jarabe/journal/palettes.py:63 ../src/jarabe/view/palettes.py:62
+msgid "Resume"
+msgstr ""
+
+#: ../src/jarabe/desktop/meshbox.py:445
+#: ../src/jarabe/frame/activitiestray.py:221
+msgid "Join"
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:18
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:35
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/jarabe/desktop/schoolserver.py:40
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:226
+#: ../src/jarabe/frame/activitiestray.py:655
+msgid "Decline"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:608
+#, python-format
+msgid "%dB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:610
+#, python-format
+msgid "%dKB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:612
+#, python-format
+msgid "%dMB"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:629
+#, python-format
+msgid "%s of %s"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:640
+#, python-format
+msgid "Transfer from %r"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:650
+msgid "Accept"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:673
+#: ../src/jarabe/frame/activitiestray.py:780
+#, python-format
+msgid "%s (%s)"
+msgstr ""
+
+#: ../src/jarabe/frame/activitiestray.py:751
+#, python-format
+msgid "Transfer to %r"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:52
+msgid "Remove"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:57
+#: ../src/jarabe/frame/clipboardmenu.py:80
+msgid "Open"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardmenu.py:85
+msgid "Open with"
+msgstr ""
+
+#: ../src/jarabe/frame/clipboardobject.py:47
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:36
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:38
+msgid "Group"
+msgstr ""
+
+#: ../src/jarabe/frame/zoomtoolbar.py:40
+msgid "Home"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:124
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:174 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr ""
+
+#: ../src/jarabe/intro/window.py:191
+msgid "Next"
+msgstr ""
+
+#: ../src/jarabe/journal/collapsedentry.py:243
+#: ../src/jarabe/journal/expandedentry.py:159
+#: ../src/jarabe/journal/palettes.py:57
+msgid "Untitled"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:205
+msgid "No preview"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:224
+msgid "Participants:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:247
+msgid "Description:"
+msgstr ""
+
+#: ../src/jarabe/journal/expandedentry.py:273
+msgid "Tags:"
+msgstr ""
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:65
+msgid "Search"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:124
+msgid "Anytime"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Today"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past year"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:141
+msgid "Anyone"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "My friends"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:144
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:271
+msgid "Anything"
+msgstr ""
+
+#: ../src/jarabe/journal/journaltoolbox.py:347
+#: ../src/jarabe/journal/palettes.py:81
+msgid "Copy"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:66 ../src/jarabe/view/palettes.py:111
+msgid "Start"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:40
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:41
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/jarabe/journal/listview.py:369
+msgid "Clear search"
+msgstr ""
+
+#: ../src/jarabe/journal/misc.py:92
+msgid "No date"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr ""
+
+#: ../src/jarabe/journal/objectchooser.py:136
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:64
+msgid "Resume with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:67
+msgid "Start with"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:89
+msgid "Send to"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:167
+msgid "No friends present"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:172
+msgid "No valid connection found"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:200
+msgid "No activity to resume entry"
+msgstr ""
+
+#: ../src/jarabe/journal/palettes.py:202
+msgid "No activity to start entry"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:61
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:64
+msgid "Make friend"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:81
+msgid "My Settings"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:86
+msgid "Logout"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:91
+msgid "Restart"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:96
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/jarabe/view/buddymenu.py:131
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:43
+msgid "Starting..."
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:73
+msgid "Stop"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:145
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:149
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:201
+msgid "Show contents"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:223 ../src/jarabe/view/palettes.py:272
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/jarabe/view/palettes.py:248
+msgid "Unmount"
+msgstr ""
diff --git a/shell/po/ur.po b/shell/po/ur.po
new file mode 100644
index 0000000..1bc0263
--- /dev/null
+++ b/shell/po/ur.po
@@ -0,0 +1,743 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-07-23 07:44-0400\n"
+"PO-Revision-Date: 2008-08-05 23:34-0400\n"
+"Last-Translator: Huda Sarfraz <huda.sarfraz@nu.edu.pk>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: ../src/intro/intro.py:65 ../src/controlpanel/view/aboutme.py:100
+msgid "Name:"
+msgstr "نام:"
+
+#: ../src/intro/intro.py:94
+msgid "Click to change color:"
+msgstr "رنگ تبديل کرنے کے ليے کلک کريں:"
+
+#: ../src/intro/intro.py:145
+msgid "Back"
+msgstr "واپس"
+
+#: ../src/intro/intro.py:159 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr "مکمل"
+
+#: ../src/intro/intro.py:162
+msgid "Next"
+msgstr "آگے"
+
+#: ../src/view/BuddyMenu.py:58
+msgid "Remove friend"
+msgstr "دوست کو ہٹائيں"
+
+#: ../src/view/BuddyMenu.py:61
+msgid "Make friend"
+msgstr "دوست بنائيں"
+
+#: ../src/view/BuddyMenu.py:91
+#, python-format
+msgid "Invite to %s"
+msgstr "%s کی دعوت دیں"
+
+#: ../src/view/clipboardmenu.py:48
+msgid "Remove"
+msgstr "ہٹائيں"
+
+#: ../src/view/clipboardmenu.py:53 ../src/view/clipboardmenu.py:79
+msgid "Open"
+msgstr "کھوليں"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../src/view/clipboardmenu.py:63 ../src/view/home/HomeBox.py:86
+msgid "Keep"
+msgstr "رکھيں"
+
+#: ../src/view/clipboardmenu.py:84
+msgid "Open with"
+msgstr "اس کے ساتھہ کھولیں"
+
+#: ../src/view/clipboardmenu.py:216
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "کلپ بورڈ آبجیکٹ: %s."
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr "اصل قسم:"
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr "اجاذت دينے کی قسم:"
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr "خفیہ کاری قسم:"
+
+#: ../src/view/Shell.py:240
+msgid "Screenshot"
+msgstr "سکرين شاٹ"
+
+#: ../src/view/home/HomeBox.py:80
+msgid "Confirm erase"
+msgstr "مٹانا کنفرم کريں"
+
+#: ../src/view/home/HomeBox.py:82
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "مٹانا تصدیق کريں: کيا آپ مستقل طور پر اس کو مٹانا چاھتے ہيں %s؟"
+
+#: ../src/view/home/HomeBox.py:89 ../src/view/palettes.py:120
+msgid "Erase"
+msgstr "مٹائيں"
+
+#: ../src/view/home/HomeBox.py:215
+msgid "List view"
+msgstr "فہرست نظارہ"
+
+#: ../src/view/home/HomeBox.py:216
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/view/home/HomeBox.py:273
+msgid "Favorites view"
+msgstr "پسندیدگان نظارہ"
+
+#: ../src/view/home/HomeBox.py:274
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/HomeBox.py:282
+msgid "Freeform"
+msgstr "فری فارم"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/HomeBox.py:289
+msgid "Ring"
+msgstr "پليٹ"
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr "کنيکٹ"
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr "منقطع کریں"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr "رابطہ کٹ رہا ہے۔۔۔"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:152
+msgid "Connecting..."
+msgstr "کنيکشن مل رہا ہے۔۔۔"
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:159
+msgid "Connected"
+msgstr "کنيکشن ہو گيا ہے"
+
+#: ../src/view/home/MeshBox.py:211 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr "ميش نيٹ ورک"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../src/view/home/MeshBox.py:214 ../src/view/devices/network/wireless.py:119
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr "کٹ کريں۔۔۔"
+
+#: ../src/view/home/MeshBox.py:302 ../src/view/palettes.py:61
+msgid "Resume"
+msgstr "پھر شروع کريں"
+
+#: ../src/view/home/MeshBox.py:307 ../src/view/frame/activitiestray.py:205
+msgid "Join"
+msgstr "شرکت کريں"
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr "ميری بيٹری"
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr "چارج کر رہا ہے"
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr "پاور بہت کم رہ گئی ہے"
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d رہ گئے ہيں"
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr "چارج ہو گئی ہے"
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr "ميرے سپيکرز"
+
+#: ../src/view/devices/speaker.py:119
+msgid "Unmute"
+msgstr "ان ميوٹ"
+
+#: ../src/view/devices/speaker.py:122
+msgid "Mute"
+msgstr "ميوٹ"
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr "منقطع ہو گیا"
+
+#: ../src/view/devices/network/wireless.py:137
+msgid "Channel"
+msgstr "چينل"
+
+#: ../src/view/frame/zoomtoolbar.py:34
+msgid "Neighborhood"
+msgstr "ميرے پڑوسی"
+
+#: ../src/view/frame/zoomtoolbar.py:36
+msgid "Group"
+msgstr "گروپ"
+
+#: ../src/view/frame/zoomtoolbar.py:38
+msgid "Home"
+msgstr "گھر"
+
+#: ../src/view/frame/zoomtoolbar.py:40
+msgid "Activity"
+msgstr "سرگرمی"
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr "شوگر-کنٹرول-پينل:ايک ہی نام کے ساتھہ کافی آپشن ملی ہيں: %s موڈيول: %r"
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "شوگر-کنٹرول-پينل: کی=%s يہ آپشن موجود نہيں ہے"
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "شوگر-کنٹرول-پينل:%s "
+
+#: ../src/controlpanel/cmd.py:33
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" "
+msgstr ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+"Control for the sugar environment. \n"
+"Options: \n"
+"-h show this help message and exit \n"
+"-l list all the available options \n"
+"-h key show information about this key \n"
+"-g key get the current value of the key \n"
+"-s key set the current value for the key \n"
+" "
+
+#: ../src/controlpanel/cmd.py:45
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "نئی تبديلیاں عمل میں لانے کے لیے آپ کو شوگر پھر شروع کرنا ہو گا۔\n"
+
+#: ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr "منسوخ کريں"
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:294
+msgid "Ok"
+msgstr "ٹھیک ہے"
+
+#: ../src/controlpanel/sectionview.py:34 ../src/controlpanel/gui.py:260
+msgid "Changes require restart"
+msgstr "دوبارہ چلا کر تبديلياں عمل ميں لائيں"
+
+#: ../src/controlpanel/gui.py:259
+msgid "Warning"
+msgstr "وارننگ"
+
+#: ../src/controlpanel/gui.py:263
+msgid "Cancel changes"
+msgstr "تبديلياں ختم کريں"
+
+#: ../src/controlpanel/gui.py:267
+msgid "Later"
+msgstr "بعد ميں"
+
+#: ../src/controlpanel/gui.py:271
+msgid "Restart now"
+msgstr "ابھی دوبارہ چلائيں"
+
+#: ../src/controlpanel/model/aboutme.py:44
+msgid "You must enter a name."
+msgstr "آپ کو ضرور ايک نام دينا ہے"
+
+#: ../src/controlpanel/model/aboutme.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "سٹروک: رنگ=%s ہيو=%s"
+
+#: ../src/controlpanel/model/aboutme.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr "سٹروک: %s"
+
+#: ../src/controlpanel/model/aboutme.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "بھر ديں: رنگ=%s ہيو=%s"
+
+#: ../src/controlpanel/model/aboutme.py:76
+#, python-format
+msgid "fill: %s"
+msgstr "بھر ديں: %s"
+
+#: ../src/controlpanel/model/aboutme.py:87
+msgid "Error in specified color modifiers."
+msgstr "اختصاص کردہ رنگ ترمیم کاروں میں نقص۔"
+
+#: ../src/controlpanel/model/aboutme.py:90
+msgid "Error in specified colors."
+msgstr "اختصاص کردہ رنگوں میں نقص۔"
+
+#: ../src/controlpanel/model/aboutxo.py:24
+msgid "Not available"
+msgstr "دستیاب نہيں"
+
+#: ../src/controlpanel/model/datetime.py:85
+msgid "Error timezone does not exist."
+msgstr "نقص، ٹائیم زون موجود نہیں ہے۔"
+
+#: ../src/controlpanel/model/frame.py:38 ../src/controlpanel/model/frame.py:60
+msgid "Value must be an integer."
+msgstr "انٹيجر ويليو ہونی چاھيے۔"
+
+#: ../src/controlpanel/model/language.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "رسائی ممکن نہيں~/.n18. سٹينڈرڈ بنائيں."
+
+#: ../src/controlpanel/model/language.py:104
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "کوڈ=%s کی زبان تعین نہیں کی جا سکی۔"
+
+#: ../src/controlpanel/model/language.py:121
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "معاف کيجيے ميں '%s' نہيں بولتا/بولتی۔"
+
+#: ../src/controlpanel/model/network.py:48
+msgid "You must enter a server."
+msgstr "ايک سکول سرور ضرور لکھیں۔"
+
+#: ../src/controlpanel/model/network.py:63
+msgid "State is unknown."
+msgstr "نامعلوم حالت"
+
+#: ../src/controlpanel/model/network.py:83
+msgid "Error in specified radio argument use on/off."
+msgstr "اختصاص کردہ ریڈیو آرگیومنٹ میں نقص، آن/آف استعمال کریں۔"
+
+#: ../src/controlpanel/model/power.py:57
+msgid "Error in automatic pm argument, use on/off."
+msgstr "خودکار pm برہان میں نقص، آن/آف استعمال کریں۔"
+
+#: ../src/controlpanel/model/power.py:86
+msgid "Error in extreme pm argument, use on/off."
+msgstr "ایکسٹریم pm برہان میں نقص، آن/آف استعمال کریں۔"
+
+#: ../src/controlpanel/view/aboutme.py:32
+msgid "About Me"
+msgstr "ميرے بارے ميں"
+
+#: ../src/controlpanel/view/aboutme.py:134
+msgid "Click to change your color:"
+msgstr "رنگ تبديل کرنے کے ليے کلک کريں:"
+
+#: ../src/controlpanel/view/aboutxo.py:26
+msgid "About my XO"
+msgstr "ميرے XO کے بارے ميں"
+
+#: ../src/controlpanel/view/aboutxo.py:47
+msgid "Identity"
+msgstr "پہچان"
+
+#: ../src/controlpanel/view/aboutxo.py:56
+msgid "Serial Number:"
+msgstr "سيريل نمبر:"
+
+#: ../src/controlpanel/view/aboutxo.py:79
+msgid "Software"
+msgstr "Software"
+
+#: ../src/controlpanel/view/aboutxo.py:88
+msgid "Build:"
+msgstr "سسٹم:"
+
+#: ../src/controlpanel/view/aboutxo.py:103
+msgid "Firmware:"
+msgstr "فرم ویئر"
+
+#: ../src/controlpanel/view/datetime.py:29
+msgid "Date & Time"
+msgstr "تاريخ & وقت"
+
+#: ../src/controlpanel/view/datetime.py:72
+msgid "Timezone"
+msgstr "ٹائم زون"
+
+#: ../src/controlpanel/view/frame.py:28
+msgid "Frame"
+msgstr "فريم"
+
+#: ../src/controlpanel/view/frame.py:30
+msgid "never"
+msgstr "کبھی نہیں"
+
+#: ../src/controlpanel/view/frame.py:31
+msgid "instantaneous"
+msgstr "اچانک"
+
+#: ../src/controlpanel/view/frame.py:32
+#, python-format
+msgid "%s seconds"
+msgstr "%s سيکنڈ"
+
+#: ../src/controlpanel/view/frame.py:56
+msgid "Activation Delay"
+msgstr "ايکٹيويشن وقفہ"
+
+#: ../src/controlpanel/view/frame.py:80
+msgid "Corner"
+msgstr "کونہ"
+
+#: ../src/controlpanel/view/frame.py:115
+msgid "Edge"
+msgstr "کنارہ"
+
+#: ../src/controlpanel/view/language.py:29
+#: ../src/controlpanel/view/language.py:74
+msgid "Language"
+msgstr "زبان"
+
+#: ../src/controlpanel/view/network.py:28
+msgid "Network"
+msgstr "نيٹ ورک"
+
+#: ../src/controlpanel/view/network.py:53
+msgid "Wireless"
+msgstr "وائيرليس"
+
+#: ../src/controlpanel/view/network.py:61
+msgid "Radio:"
+msgstr "ریڈيو:"
+
+#: ../src/controlpanel/view/network.py:94
+msgid "Mesh"
+msgstr "ميش"
+
+#: ../src/controlpanel/view/network.py:103
+msgid "Server:"
+msgstr "سکول سرور:"
+
+#: ../src/controlpanel/view/power.py:27
+msgid "Power"
+msgstr "پاور"
+
+#: ../src/controlpanel/view/power.py:51
+msgid "Power management"
+msgstr "پاور کنٹرول"
+
+#: ../src/controlpanel/view/power.py:61
+msgid "Automatic power management (increases battery life)"
+msgstr "آٹو ميٹک پاور کنٹرول(بیٹری کا دورانيہ ذيادہ کرنے کے ليے)"
+
+#: ../src/controlpanel/view/power.py:89
+msgid ""
+"Extreme power management (disables wireless radio, increases battery life)"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr "سکول کے ميش پورٹل کے ساتھہ ملا ہوا ہے"
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr " سکول ميش پورٹل ڈھونڈ رہا ہے ..."
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr "‌XO ميش پورٹل کے ساتھہ جڑا ہوا ہے"
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr "XO ميش پورٹل ڈھونڈ رہا ہے ..."
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr "سادہ ميش کے ساتھ جڑا ہوا ہے"
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr "سادہ ميش شروع کر رہا ہے"
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr "نامعلوم ميش"
+
+#: ../src/view/frame/activitiestray.py:210
+msgid "Decline"
+msgstr "منظور نہیں ہوا"
+
+#: ../src/view/home/favoritesview.py:285
+msgid "Registration Failed"
+msgstr "رجسٹريشن نہيں ہوئی"
+
+#: ../src/view/home/favoritesview.py:286
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/view/home/favoritesview.py:288
+msgid "Registration Successful"
+msgstr "رجسٹريشن ہو گئی"
+
+#: ../src/view/home/favoritesview.py:289
+msgid "You are now registered with your school server."
+msgstr "اب آپ اپنے سکول سرور کے ساتھہ رجسٹرڈ ہيں۔"
+
+#: ../src/view/home/favoritesview.py:405
+msgid "Control Panel"
+msgstr "کنٹرول پينل"
+
+#: ../src/view/home/favoritesview.py:416
+msgid "Restart"
+msgstr "دوبارہ چلائيں"
+
+#: ../src/view/home/favoritesview.py:421
+msgid "Shutdown"
+msgstr "بند کريں"
+
+#: ../src/view/home/favoritesview.py:427
+msgid "Register"
+msgstr "رجسٹر کريں"
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr "شروع ہو رہا ہے ..."
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr "روکیں"
+
+#: ../src/view/palettes.py:104
+msgid "Start"
+msgstr "شروع کريں"
+
+#: ../src/view/palettes.py:132
+msgid "Remove favorite"
+msgstr "پسنديدہ ختم کريں"
+
+#: ../src/view/palettes.py:136
+msgid "Make favorite"
+msgstr "پسندیدہ بنائيں"
+
+#: ../src/view/palettes.py:185
+msgid "Show contents"
+msgstr "مشمولات دکھائيں"
+
+#: ../src/view/palettes.py:209
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB dخالی"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "off"
+#~ msgstr "آف"
+
+#~ msgid "on"
+#~ msgstr "آن"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "اجازت سے انکار۔ یہ میتھڈ چلانے کے لیے آپ کو بھر بوٹ کرنا ہو گا۔"
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "ٹائیم زون پڑھنے میں نقص"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "ٹائیم زون نقل کرنے میں (%s سے) نقص: %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "ٹائیم زون کی اجازت بدل رہا ہے: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "اس XO کے بارے ميں"
+
+#~ msgid "Add to journal"
+#~ msgstr "جریدے ميں شامل کريں"
+
+#~ msgid "Reboot"
+#~ msgstr "پھر بوٹ کریں"
+
+#~ msgid "My Battery life"
+#~ msgstr "ميری بيٹری کی زندگی"
+
+#~ msgid "Battery charging"
+#~ msgstr "بيٹری چارج ہو رہی ہے"
+
+#~ msgid "Battery discharging"
+#~ msgstr "بیٹری ڈسچارج ہو رہی ہے"
+
+#~ msgid "Battery fully charged"
+#~ msgstr "ببيٹری پوری چارج ہے"
+
+#~ msgid "Share with:"
+#~ msgstr "حصہ داری کریں از:"
+
+#~ msgid "Private"
+#~ msgstr "ذاتی"
+
+#~ msgid "My Neighborhood"
+#~ msgstr "ميرا گرد و نواح"
+
+#~ msgid "Undo"
+#~ msgstr "کالعدم کريں"
+
+#~ msgid "Redo"
+#~ msgstr "اعادہ کريں"
+
+#~ msgid "Copy"
+#~ msgstr "نفل کريں"
+
+#~ msgid "Paste"
+#~ msgstr "جوڑيں"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s سرگرمی"
+
+#~ msgid "Keep error"
+#~ msgstr "رکھنے میں نقص"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "رکھنے میں نقص: تمام تبديلياں ضائع ہو جائیں گی"
+
+#~ msgid "Don't stop"
+#~ msgstr "نہیں روکیں"
+
+#~ msgid "Stop anyway"
+#~ msgstr "پھر بھی روکيں"
+
+#~ msgid "Continue"
+#~ msgstr "جاری رکھیں"
+
+#~ msgid "OK"
+#~ msgstr "ٹھیک ہے"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d سال"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d سال"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d مہينہ"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d مہينے"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d ہفتہ"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d ہفتے"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d دن"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d دن"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d گھنٹہ"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d گھنٹے"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d منٹ"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d منٹ"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d سيکن"
+
+#~ msgid " and "
+#~ msgstr "_اور_"
+
+#~ msgid ", "
+#~ msgstr "،_"
diff --git a/shell/po/vi.po b/shell/po/vi.po
new file mode 100644
index 0000000..84268c2
--- /dev/null
+++ b/shell/po/vi.po
@@ -0,0 +1,1415 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-11 00:32-0500\n"
+"PO-Revision-Date: 2010-03-15 05:42+0200\n"
+"Last-Translator: Chris <cjl@laptop.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: vi\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"
+"X-Generator: Pootle 2.0.3\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "Giới thiệu mình"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "Bạn cần phải nhập một tên."
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "nét vẽ: màu=%s sắc=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "nét vẽ: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "tô màu : màu=%s sắc=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "tô màu : %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "Sai xác định sự sửa đổi màu."
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "Sai xác định màu."
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "Tên:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "Nhấn chuột để thay đổi màu :"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "Giới thiệu máy tính này"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "Không sẵn sàng"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "Cá tính"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "Số sản xuất:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "Phần mềm"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "Bản xây dựng:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "Phần vững:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "Phần vững không dây:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "Tác quyền và Giấy phép"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+"Sugar là giao diện người dùng đồ họa thích hợp với bạn. Sugar là phần mềm tự "
+"do, được bao quát bởi Giấy Phép Công Cộng GNU (GPL), thì bạn có quyền sửa "
+"đổi và/hay phân phối lại bản sao nó với các điều kiện GPL."
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "Giấy phép đầy đủ :"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "Ngày và Giờ"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "Lỗi: múi giờ không tồn tại."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:33
+msgid "Timezone"
+msgstr "Múi giờ"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "Khung"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "Giá trị phải là một số nguyên."
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "không bao giờ"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "ngay lập tức"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s giây"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "Khoảng đợi kích hoạt"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "Góc"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "Cạnh"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "Bàn phím"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "Mô hình bàn phím"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "(Tổ hợp) phím để chuyển đổi bố trí"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "Bố trí Bàn phím"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "Ngôn ngữ"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+"Không thể truy cập đến thư mục « ~/.i18n ». Hãy tạo thiết lập tiêu chuẩn."
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "Không thể quyết định ngôn ngữ cho mã=%s."
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "Tiếc là chương trình này không hiểu « %s »."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr ""
+"Thêm các ngôn ngữ theo thứ tự đã thích. Nếu không có bản dịch thì dùng ngôn "
+"ngữ kế tiếp trong danh sách này."
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr "Cấu hình mô-đêm"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:90
+msgid "Username:"
+msgstr "Tên người dùng:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:101
+msgid "Password:"
+msgstr "Mật khẩu :"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:112
+msgid "Number:"
+msgstr "Số :"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:123
+msgid "APN:"
+msgstr "APN:"
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "Mạng"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "Không rõ tình trạng."
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "Lỗi trong đối số chọn một đã ghi rõ bật/tắt."
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "Lỗi trong đối số chỉ định: dùng 0/1."
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "Không dây"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "Tắt máy thu thanh không dây để tiết kiệm thời gian chạy bằng pin"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "Thu thanh"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "Hủy lịch sử mạng nếu bạn gặp khó khăn trong việc kết nối tới mạng"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "Hủy lịch sử mạng"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "Hợp tác"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr ""
+"Máy phục vụ giống như một phòng chứa vài người khác nhau : những người cùng "
+"phòng (trên cùng một máy phục vụ) thì có thể liên lạc với nhau, ngay cả khi "
+"không phải làm cùng một việc (trên cùng một mạng)."
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "Máy phục vụ :"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "Năng lượng"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "Lỗi trong đối số tự động pm: dùng on/off."
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "Lỗi trong đối số extreme pm: dùng on/off."
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "Quản lý năng lượng"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "Tự động quản lý năng lượng (tăng thời gian chạy bằng pin)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+"Rất quản lý năng lượng (tắt máy thu thanh không dây, tăng thời gian chạy "
+"bằng pin)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "Cập nhật phần mềm"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr ""
+"Bản cập nhật phần mềm thì sửa chữa lỗi, loại trừ trường hợp có thể bị lỗ "
+"hổng bảo mật, và cung cấp tính năng mới."
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "Đang kiểm tra %s..."
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "Đang tải về %s..."
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "Đang cập nhật %s..."
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "Phần mềm vẫn còn hiện thời"
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "Bạn có dịp cài đặt %s bản cập nhật"
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "Đang kiểm tra có bản cập nhật chưa..."
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "Đang cài đặt bản cập nhật..."
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "%s bản cập nhật đã được cài đặt"
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "Cài đặt mục đã chọn"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "Kích cỡ tải về: %s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "Từ phiên bản %(current)d lên %(new)s (Kích cỡ : %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "Không có"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1 KB"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f KB"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "Pin của mình"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "Bị bỏ"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "Đang sạc"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "Pin yếu tới hạn"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "%(hour)d:%(min).2d còn lại"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "Sạc đầy"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "Địa chỉ IP: %s"
+
+#: ../extensions/deviceicon/network.py:111
+msgid "Disconnect..."
+msgstr "Ngắt kết nối..."
+
+#: ../extensions/deviceicon/network.py:116
+msgid "Create new wireless network"
+msgstr "Tạo mạng vô tuyến mới"
+
+#: ../extensions/deviceicon/network.py:122
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/desktop/meshbox.py:248 ../src/jarabe/desktop/meshbox.py:537
+msgid "Connecting..."
+msgstr "Đang kết nối..."
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:126
+#: ../extensions/deviceicon/network.py:198
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:254 ../src/jarabe/desktop/meshbox.py:543
+msgid "Connected"
+msgstr "Đã kết nối"
+
+#: ../extensions/deviceicon/network.py:158
+msgid "Channel"
+msgstr "Kênh"
+
+#: ../extensions/deviceicon/network.py:173
+msgid "Wired Network"
+msgstr "Mạng theo dây"
+
+#: ../extensions/deviceicon/network.py:201
+msgid "Speed"
+msgstr "Tốc độ"
+
+#: ../extensions/deviceicon/network.py:228
+msgid "Wireless modem"
+msgstr "Mô-đem vô tuyến"
+
+#: ../extensions/deviceicon/network.py:276
+msgid "Please wait..."
+msgstr "Hãy đợi..."
+
+#: ../extensions/deviceicon/network.py:279
+#: ../src/jarabe/desktop/meshbox.py:164 ../src/jarabe/desktop/meshbox.py:494
+msgid "Connect"
+msgstr "Kết nối"
+
+#: ../extensions/deviceicon/network.py:280
+msgid "Disconnected"
+msgstr "Bị ngắt kết nối"
+
+#: ../extensions/deviceicon/network.py:283
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "Thôi"
+
+#: ../extensions/deviceicon/network.py:287
+#: ../src/jarabe/desktop/meshbox.py:168
+msgid "Disconnect"
+msgstr "Ngắt kết nối"
+
+#: ../extensions/deviceicon/network.py:530
+#, python-format
+msgid "%s's network"
+msgstr "Mạng của %s"
+
+#: ../extensions/deviceicon/network.py:597
+#: ../extensions/deviceicon/network.py:656
+msgid "Mesh Network"
+msgstr "Mạng mắc lưới"
+
+#: ../extensions/deviceicon/network.py:857
+#, python-format
+msgid "Data sent %d kb / received %d kb"
+msgstr "Dữ liệu đã gửi %d kb / đã nhận %d kb"
+
+#: ../extensions/deviceicon/network.py:868
+msgid "Connection time "
+msgstr "Thời gian kết nối "
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "Loa của mình"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "Bỏ câm"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "Câm"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "Mesh"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "Nhóm"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "Nhà"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "Hoạt động"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "Ảnh chụp màn hình"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "Ảnh chụp màn hình « %s »"
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr ""
+"« bị tắt » để yêu cầu tên hiệu khi sơ khởi; « hệ thống » để dùng lại tên dài "
+"của tài khoản UNIX."
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Backup URL"
+msgstr "URL sao lưu"
+
+#: ../data/sugar.schemas.in.h:3
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr ""
+"Màu của biểu tượng XO được dùng trong toàn môi trường. Chuỗi bao gồm màu nét "
+"và màu tô đầy, định dạng là RBG, v.d. #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Corner Delay"
+msgstr "Trễ góc"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Default font face"
+msgstr "Mặt chữ mặc định"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font size"
+msgstr "Cỡ phông mặc định"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default nick"
+msgstr "Tên hiệu mặc định"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Delay for the activation of the frame using the corners."
+msgstr "Khoảng đợi khi kích hoạt khung dùng góc."
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the edges."
+msgstr "Khoảng đợi khi kích hoạt khung dùng cạnh."
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Edge Delay"
+msgstr "Trễ cạnh"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Favorites Layout"
+msgstr "Bố trí Ưa thích"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Favorites resume mode"
+msgstr "Chế độ tiếp tục lại mục ưa thích"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Font face that is used throughout the desktop."
+msgstr "Mặt phông chữ được sử dụng trên toàn bộ môi trường."
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Font size that is used throughout the desktop."
+msgstr "Kích cỡ phông chữ được sử dụng trên toàn bộ môi trường."
+
+#: ../data/sugar.schemas.in.h:15
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr ""
+"TRUE (đúng) thì Sugar sẽ cấp các người khác trên máy phục vụ Jabber có quyền "
+"tìm kiếm qua chúng ta."
+
+#: ../data/sugar.schemas.in.h:16
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "TRUE (đúng) thì Sugar hiển thị một tùy chọn « Đăng xuất »."
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Jabber Server"
+msgstr "Máy phục vụ Jabber"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Keyboard layouts"
+msgstr "Bố trí bàn phím"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Keyboard model"
+msgstr "Mô hình bàn phím"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Keyboard options"
+msgstr "Tuỳ chọn bàn phím"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Layout of the favorites view."
+msgstr "Bố trí của ô xem các mục ưa thích."
+
+#: ../data/sugar.schemas.in.h:22
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr "Danh sách các bố trí bàn phím. Mỗi mục nên có dạng « bố_trí(biến_đổi) »"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "List of keyboard options."
+msgstr "Danh sách các tuỳ chọn về bàn phím."
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Power Automatic"
+msgstr "Tự động năng lượng"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Power Automatic."
+msgstr "Tự động năng lượng."
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Power Extreme"
+msgstr "Năng lượng cực"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Power Extreme."
+msgstr "Năng lượng cực."
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Publish to Gadget"
+msgstr "Xuất tới Gadget"
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Setting for muting the sound device."
+msgstr "Thiết lập để câm thiết bị âm thanh."
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Show Log out"
+msgstr "Hiện Đăng xuất"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Sound Muted"
+msgstr "Âm câm"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "The keyboard model to be used"
+msgstr "Mô hình bàn phím cần dùng"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Timezone setting for the system."
+msgstr "Thiết lập múi giờ cho hệ thống."
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Url of the jabber server to use."
+msgstr "Địa chỉ URL của máy phục vụ Jabber cần dùng."
+
+#: ../data/sugar.schemas.in.h:36
+msgid "Url where the backup is saved to."
+msgstr "Địa chỉ URL vào đó lưu bản sao lưu."
+
+#: ../data/sugar.schemas.in.h:37
+msgid "User Color"
+msgstr "Màu người dùng"
+
+#: ../data/sugar.schemas.in.h:38
+msgid "User Name"
+msgstr "Tên người dùng"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "User name that is used throughout the desktop."
+msgstr "Tên người dùng được sử dụng trên toàn bộ môi trường."
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Volume Level"
+msgstr "Cấp âm"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Volume level for the sound device."
+msgstr "Cấp âm lượng cho thiết bị âm thanh."
+
+#: ../data/sugar.schemas.in.h:42
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr ""
+"Khi trong chế độ tiếp tục lại, cú nhấn vào một biểu tượng ưa thích sẽ tiếp "
+"tục lại mục nhập cuối cùng cho hoạt động đó."
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+"sugar-control-panel: CẢNH BÁO : tìm nhiều tùy chọn cùng tên: mô-đun %s: %r"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "sugar-control-panel: khoá=%s không phải là một tùy chọn sẵn sàng"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "sugar-control-panel: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"Sử dụng: sugar-control-panel [ tùy_chọn ] khoá [ đối_số ... ]\n"
+" Điều khiển môi trường sugar.\n"
+"\n"
+" Tùy chọn:\n"
+" -h hiển thị trợ giúp này và thoát\n"
+" -l liệt kê tất cả các tùy chọn sẵn sàng\n"
+" -h khoá hiển thị thông tin về khoá này\n"
+" -g khoá lấy giá trị hiện thời của khoá này\n"
+" -s khoá đặt giá trị hiện thời của khoá này\n"
+" -c khoá xoá giá trị hiện thời của khoá\n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "Để áp dụng các thay đổi thì cần phải khởi chạy lại pn sugar.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "Cảnh báo"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "Có thay đổi thì cần phải khởi chạy lại"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "Thôi thay đổi"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "Về sau"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "Khởi chạy lại ngay"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "Hoàn tất"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "OK"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "Phiên bản %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "Xác nhận việc xoá"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "Xác nhận việc xoá: bạn có muốn xoá hẳn %s không?"
+
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "Giữ"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:105
+msgid "Erase"
+msgstr "Xoá"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "Bỏ Ưa thích"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "Đặt Ưa thích"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "Dạng tự do"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "Vòng"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "Xoắn ốc"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "Hộp"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "Hình giác"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "Lỗi đăng ký"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "Đang ký thành công"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "Bạn đã đăng ký với máy phục vụ trường học."
+
+#: ../src/jarabe/desktop/favoritesview.py:630
+msgid "Register"
+msgstr "Đăng ký"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "Cập nhật Phần mềm"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "Cập nhật các hoạt động để đảm bảo tính tương thích với phần mềm mới"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "Kiểm tra ngay"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "Xem danh sách"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "Xem Ưa thích"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "Kiểu khoá:"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "Cách xác thực:"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "WPA và WPA2 Cá nhân"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "Bảo mật Không dây:"
+
+#: ../src/jarabe/desktop/meshbox.py:492
+#, python-format
+msgid "Mesh Network %d"
+msgstr "Mạng mắc lưới %d"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:629
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:65 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "Tiếp tục"
+
+#: ../src/jarabe/desktop/meshbox.py:634
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "Vào"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "Không thể kết nối tới máy phục vụ."
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "Máy phục vụ không thể hoàn tất yêu cầu."
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "Từ chối"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "%s trên %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "Truyền từ %r"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "Chấp nhận"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr "Hủy"
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "Truyền tới %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "Bỏ"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "Mở"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "Mở bằng"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "đoạn trích %s"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "Hàng xóm"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "Nhấn vào để thay đổi mảu:"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "Lùi"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "Tiếp"
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:59
+msgid "Untitled"
+msgstr "Không tên"
+
+#: ../src/jarabe/journal/expandedentry.py:243
+msgid "No preview"
+msgstr "Không xem thử"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Kind: %s"
+msgstr "Kiểu : %s"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+msgid "Unknown"
+msgstr "Không rõ"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Date: %s"
+msgstr "Ngày: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Size: %s"
+msgstr "Kích cỡ : %s"
+
+#: ../src/jarabe/journal/expandedentry.py:286 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "Không có ngày tháng"
+
+#: ../src/jarabe/journal/expandedentry.py:293
+msgid "Participants:"
+msgstr "Người dự :"
+
+#: ../src/jarabe/journal/expandedentry.py:316
+msgid "Description:"
+msgstr "Mô tả:"
+
+#: ../src/jarabe/journal/expandedentry.py:341
+msgid "Tags:"
+msgstr "Thẻ:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "Nhật ký"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "Tìm kiếm"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "Lúc nào"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "Hôm nay"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "Kể từ ngày hôm qua"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "Tuần qua"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "Tháng qua"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "Năm qua"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "Bất cứ ai"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "Bạn bè"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "Cùng lớp"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "Bất cứ gì"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:83
+msgid "Copy"
+msgstr "Chép"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:68
+msgid "Start"
+msgstr "Khởi chạy"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "Nhật ký của bạn còn trống"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "Không tìm thấy"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "Xoá trường tìm"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "Nhật ký của bạn còn trống"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+"Hãy xoá một số mục nhập Nhật ký cũ để giải phóng thêm sức chứa cho mục nhập "
+"mới."
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "Hiện Nhật ký"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "Chọn một đối tượng"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "Đóng"
+
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Resume with"
+msgstr "Tiếp tục lại với"
+
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start with"
+msgstr "Bắt đầu với"
+
+#: ../src/jarabe/journal/palettes.py:91
+msgid "Send to"
+msgstr "Gửi cho"
+
+#: ../src/jarabe/journal/palettes.py:100
+msgid "View Details"
+msgstr "Xem chi tiết"
+
+#: ../src/jarabe/journal/palettes.py:178
+msgid "No friends present"
+msgstr "Bạn bè không có mặt"
+
+#: ../src/jarabe/journal/palettes.py:183
+msgid "No valid connection found"
+msgstr "Không tìm thấy kết nối hợp lệ"
+
+#: ../src/jarabe/journal/palettes.py:211
+msgid "No activity to resume entry"
+msgstr "Không có hoạt động để tiếp tục nhập vào"
+
+#: ../src/jarabe/journal/palettes.py:213
+msgid "No activity to start entry"
+msgstr "Không có hoạt động cần lại để bắt đầu nhập vào"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "Bỏ bạn"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "Kết bạn"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "Tắt máy"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "Đăng xuất"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "Thiết lập của mình"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "Mời vào %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "Đang khởi chạy..."
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr "Xem nguồn"
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "Dừng"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr "Khởi chạy mới"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "Hiện nội dung"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "%(free_space)d MB còn rảnh"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "Thể hiện nguồn"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "Nguồn"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "Nguồn bó hoạt động"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "Xem nguồn: %r"
+
+#~ msgid "Title"
+#~ msgstr "Tên"
+
+#~ msgid "Version"
+#~ msgstr "Phiên bản"
+
+#~ msgid "Date"
+#~ msgstr "Ngày"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "Không thể lấy dữ liệu cần thiết để đăng ký."
+
+#~ msgid "Unmount"
+#~ msgstr "Bỏ lắp"
+
+#~ msgid "Restart"
+#~ msgstr "Khởi chạy lại"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+
+#~ msgid "Document"
+#~ msgstr "Tài liệu"
+
+#~ msgid "Resume by default"
+#~ msgstr "Tiếp tục lại theo mặc định"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "Cách mật mã: "
+
+#~ msgid "Disconnecting..."
+#~ msgstr "Đang ngắt kết nối..."
+
+#~ msgid "About my XO"
+#~ msgstr "Giới thiệu XO của mình"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "Có kết nối tới một cổng chính Mesh trường học"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "Đang tìm một cổng chính Mesh trường học..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "Có kết nối tới một cổng chính Mesh XO"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "Đang tìm một cổng chính Mesh XO..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "Có kết nối tới một Mesh đơn giản"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "Đang khởi chạy một Mesh đơn giản"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "Không rõ Mesh"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "Đối tượng bảng nháp: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "Bạn cần phải nhập một máy phục vụ."
+
+#~ msgid "Control Panel"
+#~ msgstr "Bảng điều khiển"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "Ring view"
+#~ msgstr "Xem vòng"
+
+#~ msgid "Remove from ring"
+#~ msgstr "Gỡ ra vòng"
+
+#~ msgid "Add to ring"
+#~ msgstr "Thêm vào vòng"
+
+#~ msgid "Changes require a sugar restart to take effect."
+#~ msgstr "Để thay đổi có tác động, cần phải khởi chạy lại phần mềm sugar."
+
+#~ msgid "Changes require restart to take effect"
+#~ msgstr "Để thay đổi có tác động, cần phải khởi chạy lại phần mềm"
+
+#~ msgid "Delay in milliseconds:"
+#~ msgstr "Khoảng đợi theo mili-giây: "
+
+#~ msgid "Hot Corners"
+#~ msgstr "Góc nóng"
+
+#~ msgid "Warm Edges"
+#~ msgstr "Cạnh ấm"
diff --git a/shell/po/wa.po b/shell/po/wa.po
new file mode 100644
index 0000000..63d4e34
--- /dev/null
+++ b/shell/po/wa.po
@@ -0,0 +1,764 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-25 00:30-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: ../src/intro/window.py:93 ../src/controlpanel/aboutme/view.py:100
+msgid "Name:"
+msgstr ""
+
+#: ../src/intro/window.py:125
+msgid "Click to change color:"
+msgstr ""
+
+#: ../src/intro/window.py:175 ../src/journal/detailview.py:119
+msgid "Back"
+msgstr ""
+
+#: ../src/intro/window.py:189 ../src/controlpanel/toolbar.py:61
+msgid "Done"
+msgstr ""
+
+#: ../src/intro/window.py:192
+msgid "Next"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:60
+msgid "Remove friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:63
+msgid "Make friend"
+msgstr ""
+
+#: ../src/view/BuddyMenu.py:92
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:51
+msgid "Remove"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:56 ../src/view/clipboardmenu.py:78
+msgid "Open"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:61 ../src/view/home/HomeBox.py:84
+msgid "Keep"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:83
+msgid "Open with"
+msgstr ""
+
+#: ../src/view/clipboardmenu.py:228
+#, python-format
+msgid "%s clipping"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:150
+msgid "Key Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:170
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../src/hardware/keydialog.py:251
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:17
+msgid "Cannot obtain data needed for registration."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:31
+msgid "Cannot connect to the server."
+msgstr ""
+
+#: ../src/hardware/schoolserver.py:36
+msgid "The server could not complete the request."
+msgstr ""
+
+#: ../src/view/Shell.py:251
+msgid "Screenshot"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:78
+msgid "Confirm erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:80
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:87 ../src/view/palettes.py:120
+#: ../src/journal/journaltoolbox.py:335 ../src/journal/palettes.py:75
+msgid "Erase"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:117
+msgid "Software Update"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:118
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:122 ../src/controlpanel/toolbar.py:115
+msgid "Cancel"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:124 ../src/controlpanel/gui.py:273
+msgid "Later"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:127
+msgid "Check now"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:261
+msgid "List view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:262
+msgid "<Ctrl>2"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:320
+msgid "Favorites view"
+msgstr ""
+
+#: ../src/view/home/HomeBox.py:321
+msgid "<Ctrl>1"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:97
+msgid "Connect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:106
+msgid "Disconnect"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:118
+msgid "Disconnecting..."
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:159
+msgid "Connecting..."
+msgstr ""
+
+#. TODO: show the channel number
+#: ../src/view/home/MeshBox.py:166
+msgid "Connected"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:218 ../src/view/devices/network/mesh.py:41
+#: ../src/view/devices/network/mesh.py:68
+#: ../src/view/devices/network/mesh.py:72
+msgid "Mesh Network"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:221 ../src/view/devices/network/wireless.py:125
+#: ../src/view/devices/network/mesh.py:89
+msgid "Disconnect..."
+msgstr ""
+
+#. TRANS: Action label for resuming an activity.
+#: ../src/view/home/MeshBox.py:309 ../src/view/palettes.py:61
+#: ../src/journal/journaltoolbox.py:399 ../src/journal/palettes.py:57
+msgid "Resume"
+msgstr ""
+
+#: ../src/view/home/MeshBox.py:314 ../src/view/frame/activitiestray.py:206
+msgid "Join"
+msgstr ""
+
+#: ../src/view/devices/battery.py:45
+msgid "My Battery"
+msgstr ""
+
+#: ../src/view/devices/battery.py:114
+msgid "Charging"
+msgstr ""
+
+#: ../src/view/devices/battery.py:117
+msgid "Very little power remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:123
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr ""
+
+#: ../src/view/devices/battery.py:127
+msgid "Charged"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:44
+msgid "My Speakers"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:125
+msgid "Unmute"
+msgstr ""
+
+#: ../src/view/devices/speaker.py:128
+msgid "Mute"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:67
+msgid "Disconnected"
+msgstr ""
+
+#: ../src/view/devices/network/wireless.py:143
+msgid "Channel"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr ""
+
+#: ../src/view/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:26
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:28
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:29
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr ""
+
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/controlpanel/cmd.py:35
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+
+#: ../src/controlpanel/cmd.py:48
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../src/controlpanel/toolbar.py:121 ../src/view/home/favoritesview.py:305
+msgid "Ok"
+msgstr ""
+
+#: ../src/controlpanel/sectionview.py:42 ../src/controlpanel/gui.py:265
+msgid "Changes require restart"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:264
+msgid "Warning"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:268
+msgid "Cancel changes"
+msgstr ""
+
+#: ../src/controlpanel/gui.py:277
+msgid "Restart now"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:44
+msgid "You must enter a name."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:69
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:72
+#, python-format
+msgid "stroke: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:74
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:76
+#, python-format
+msgid "fill: %s"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:87
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/model.py:90
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:32
+#: ../src/controlpanel/aboutme/__init__.py:22
+msgid "About Me"
+msgstr ""
+
+#: ../src/controlpanel/aboutme/view.py:134
+msgid "Click to change your color:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/model.py:24
+msgid "Not available"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:55
+msgid "Identity"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:64
+msgid "Serial Number:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:87
+msgid "Software"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:96
+msgid "Build:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:111
+msgid "Sugar:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:126
+msgid "Firmware:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:148
+msgid "Copyright and License"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:156
+msgid ""
+"© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:163
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/view.py:175
+msgid "Full license:"
+msgstr ""
+
+#: ../src/controlpanel/aboutxo/__init__.py:21
+msgid "About my XO"
+msgstr ""
+
+#: ../src/controlpanel/datetime/model.py:89
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../src/controlpanel/datetime/view.py:68
+msgid "Timezone"
+msgstr ""
+
+#: ../src/controlpanel/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr ""
+
+#: ../src/controlpanel/frame/model.py:38 ../src/controlpanel/frame/model.py:60
+msgid "Value must be an integer."
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:26
+msgid "never"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:27
+msgid "instantaneous"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:52
+msgid "Activation Delay"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:76
+msgid "Corner"
+msgstr ""
+
+#: ../src/controlpanel/frame/view.py:111
+msgid "Edge"
+msgstr ""
+
+#: ../src/controlpanel/frame/__init__.py:21
+msgid "Frame"
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:114
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../src/controlpanel/language/model.py:131
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../src/controlpanel/language/view.py:70
+#: ../src/controlpanel/language/__init__.py:21
+msgid "Language"
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:62
+msgid "State is unknown."
+msgstr ""
+
+#: ../src/controlpanel/network/model.py:82
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:28
+#: ../src/controlpanel/network/__init__.py:21
+msgid "Network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:54
+msgid "Wireless"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:62
+msgid "Turn of the wireless radio to save battery life"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:75
+msgid "Radio"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:91
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:100
+msgid "Discard network history"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:113
+msgid "Mesh"
+msgstr ""
+
+#: ../src/controlpanel/network/view.py:122
+msgid "Server:"
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:55
+msgid "Error in automatic pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/model.py:84
+msgid "Error in extreme pm argument, use on/off."
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:47
+msgid "Power management"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr ""
+
+#: ../src/controlpanel/power/__init__.py:21
+msgid "Power"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:111
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:113
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:116
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:118
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:121
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:123
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../src/view/devices/network/mesh.py:130
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../src/view/frame/activitiestray.py:211
+msgid "Decline"
+msgstr ""
+
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:107
+msgid "Freeform"
+msgstr ""
+
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:189
+msgid "Ring"
+msgstr ""
+
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:334
+msgid "Spiral"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:401
+msgid "Box"
+msgstr ""
+
+#. TRANS: label for the box layout in the favorites view
+#: ../src/view/home/favoriteslayout.py:442
+msgid "Triangle"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:295
+msgid "Registration Failed"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:296
+#, python-format
+msgid "%s"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:298
+msgid "Registration Successful"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:299
+msgid "You are now registered with your school server."
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:420
+msgid "Settings"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:425
+msgid "Restart"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:430
+msgid "Shutdown"
+msgstr ""
+
+#: ../src/view/home/favoritesview.py:436
+msgid "Register"
+msgstr ""
+
+#: ../src/view/palettes.py:42
+msgid "Starting..."
+msgstr ""
+
+#: ../src/view/palettes.py:72
+msgid "Stop"
+msgstr ""
+
+#. TRANS: Action label for starting an entry.
+#: ../src/view/palettes.py:104 ../src/journal/journaltoolbox.py:402
+#: ../src/journal/palettes.py:59
+msgid "Start"
+msgstr ""
+
+#: ../src/view/palettes.py:138
+msgid "Remove favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:142
+msgid "Make favorite"
+msgstr ""
+
+#: ../src/view/palettes.py:191
+msgid "Show contents"
+msgstr ""
+
+#: ../src/view/palettes.py:215
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:62
+msgid "Search"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:119
+msgid "Anytime"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:121
+msgid "Today"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:123
+msgid "Since yesterday"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/journal/journaltoolbox.py:125
+msgid "Past week"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/journal/journaltoolbox.py:127
+msgid "Past month"
+msgstr ""
+
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/journal/journaltoolbox.py:129
+msgid "Past year"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:136
+msgid "Anyone"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:138
+msgid "My friends"
+msgstr ""
+
+#: ../src/journal/journaltoolbox.py:139
+msgid "My class"
+msgstr ""
+
+#. TRANS: Item in a combo box that filters by entry type.
+#: ../src/journal/journaltoolbox.py:255
+msgid "Anything"
+msgstr ""
+
+#. TODO: Add "Start with" menu item
+#: ../src/journal/journaltoolbox.py:325 ../src/journal/palettes.py:67
+msgid "Copy"
+msgstr ""
+
+#: ../src/journal/collapsedentry.py:248 ../src/journal/expandedentry.py:176
+#: ../src/journal/palettes.py:51
+msgid "Untitled"
+msgstr ""
+
+#: ../src/journal/journalactivity.py:119 ../src/journal/volumesmanager.py:57
+msgid "Journal"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:222
+msgid "No preview"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:241
+msgid "Participants:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:266
+msgid "Description:"
+msgstr ""
+
+#: ../src/journal/expandedentry.py:292
+msgid "Tags:"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:134
+msgid "Choose an object"
+msgstr ""
+
+#: ../src/journal/objectchooser.py:139
+msgid "Close"
+msgstr ""
+
+#: ../src/journal/volumestoolbar.py:93
+msgid "Unmount"
+msgstr ""
+
+#: ../src/journal/misc.py:95
+msgid "No date"
+msgstr ""
+
+#: ../src/journal/listview.py:39
+msgid "Your Journal is empty"
+msgstr ""
+
+#: ../src/journal/listview.py:40
+msgid "No matching entries "
+msgstr ""
+
+#: ../src/journal/modalalert.py:59
+msgid "Your Journal is full"
+msgstr ""
+
+#: ../src/journal/modalalert.py:63
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr ""
+
+#: ../src/journal/modalalert.py:75
+msgid "Show Journal"
+msgstr ""
diff --git a/shell/po/yo.po b/shell/po/yo.po
new file mode 100644
index 0000000..5299db7
--- /dev/null
+++ b/shell/po/yo.po
@@ -0,0 +1,448 @@
+# translation of sugar.po to Yoruba
+# This file is distributed under the same license as the PACKAGE package.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER.
+# Fajuyitan, Sunday <ayo@wazobialinux.com>, 2006.
+# Fajuyitan, Sunday Ayo <ayo@wazobialinux.com>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2006-07-07 09:48+0100\n"
+"Last-Translator: Fajuyitan, Sunday Ayo <ayo@wazobialinux.com>\n"
+"Language-Team: Yoruba\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#: ../shell/PresenceWindow.py:62
+msgid "Who's around:"
+msgstr "Ta ló wà níbẹ̀ o o:"
+
+#: ../shell/PresenceWindow.py:104
+msgid "Share"
+msgstr "Ìpín"
+
+#: ../shell/StartPage.py:189
+msgid "Search"
+msgstr "Wádìí"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "Padà Sẹ́yìn"
+
+#: ../activities/browser/NavigationToolbar.py:23
+msgid "Forward"
+msgstr "Lọ síwájú"
+
+#: ../activities/browser/NavigationToolbar.py:29
+msgid "Reload"
+msgstr "Tun kì"
+
+#: ../shell/shell.py:333
+msgid "Everyone"
+msgstr "Gbogbo èèyàn"
+
+#: ../sugar/chat/ChatEditor.py:43
+msgid "Send"
+msgstr "Fi ránṣẹ́"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr ""
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr ""
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr ""
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr ""
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr ""
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr ""
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr ""
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr ""
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr ""
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr ""
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr ""
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr ""
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr ""
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr ""
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr ""
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr ""
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr ""
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ""
+
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr ""
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr ""
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr ""
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/zh_CN.po b/shell/po/zh_CN.po
new file mode 100644
index 0000000..bd5b1b2
--- /dev/null
+++ b/shell/po/zh_CN.po
@@ -0,0 +1,420 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-01-18 18:19+0000\n"
+"PO-Revision-Date: 2008-01-11 21:14+0000\n"
+"Last-Translator: Yuan Chao <yuanchao@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.0.2\n"
+
+#: ../shell/intro/intro.py:67
+msgid "Name:"
+msgstr "姓名:"
+
+#: ../shell/intro/intro.py:96
+msgid "Click to change color:"
+msgstr "点击来改变颜色:"
+
+#: ../shell/intro/intro.py:146
+msgid "Back"
+msgstr "后退"
+
+#: ../shell/intro/intro.py:160
+msgid "Done"
+msgstr "完成"
+
+#: ../shell/intro/intro.py:163
+msgid "Next"
+msgstr "下一步"
+
+#: ../shell/view/BuddyMenu.py:59
+msgid "Remove friend"
+msgstr "删除好友"
+
+#: ../shell/view/BuddyMenu.py:62
+msgid "Make friend"
+msgstr "结交好友"
+
+#: ../shell/view/BuddyMenu.py:84
+#, python-format
+msgid "Invite to %s"
+msgstr "邀请到%s"
+
+#: ../shell/view/clipboardmenu.py:58
+msgid "Remove"
+msgstr "删除"
+
+#: ../shell/view/clipboardmenu.py:63
+msgid "Open"
+msgstr "打开"
+
+#. self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+#. TODO: Implement stopping downloads
+#. self._stop_item.connect('activate', self._stop_item_activate_cb)
+#. self.append_menu_item(self._stop_item)
+#: ../shell/view/clipboardmenu.py:73
+msgid "Add to journal"
+msgstr "增添到日志中"
+
+#: ../shell/view/clipboardmenu.py:213
+#, python-format
+msgid "Clipboard object: %s."
+msgstr "剪贴板物件: %s."
+
+#: ../shell/hardware/keydialog.py:149
+msgid "Key Type:"
+msgstr "密钥类型:"
+
+#: ../shell/hardware/keydialog.py:169
+msgid "Authentication Type:"
+msgstr "验证类型:"
+
+#: ../shell/hardware/keydialog.py:250
+msgid "Encryption Type:"
+msgstr "加密类型:"
+
+#: ../shell/view/home/activitiesdonut.py:90
+msgid "Starting..."
+msgstr "开始..."
+
+#: ../shell/view/home/activitiesdonut.py:104 ../shell/view/home/MeshBox.py:295
+msgid "Resume"
+msgstr "继续"
+
+#: ../shell/view/home/activitiesdonut.py:111
+#: ../lib/sugar/activity/activity.py:132
+msgid "Stop"
+msgstr "停止"
+
+#: ../shell/view/Shell.py:285
+msgid "Screenshot"
+msgstr "屏幕抓图"
+
+#: ../shell/view/home/HomeBox.py:159
+msgid "Reboot"
+msgstr "重新启动"
+
+#: ../shell/view/home/HomeBox.py:164
+msgid "Shutdown"
+msgstr "关闭系统"
+
+#: ../shell/view/home/HomeBox.py:170
+msgid "Register"
+msgstr "注册"
+
+#. Only show disconnect when there's a mesh device, because mesh takes
+#. priority over the normal wireless device. NM doesn't have a "disconnect"
+#. method for a device either (for various reasons) so this doesn't
+#. have a good mapping
+#: ../shell/view/home/MeshBox.py:90 ../shell/view/home/MeshBox.py:197
+#: ../shell/view/devices/network/wireless.py:113
+#: ../shell/view/devices/network/mesh.py:83
+msgid "Disconnect..."
+msgstr "断开..."
+
+#: ../shell/view/home/MeshBox.py:195 ../shell/view/devices/network/mesh.py:37
+#: ../shell/view/devices/network/mesh.py:62
+#: ../shell/view/devices/network/mesh.py:66
+msgid "Mesh Network"
+msgstr "网状网络"
+
+#: ../shell/view/home/MeshBox.py:300
+msgid "Join"
+msgstr "加入"
+
+#: ../shell/view/devices/battery.py:38
+msgid "My Battery life"
+msgstr "我的电池状态"
+
+#: ../shell/view/devices/battery.py:94
+msgid "Battery charging"
+msgstr "电池充电中"
+
+#: ../shell/view/devices/battery.py:96
+msgid "Battery discharging"
+msgstr "电池放电中"
+
+#: ../shell/view/devices/battery.py:98
+msgid "Battery fully charged"
+msgstr "电池充电完成"
+
+#: ../shell/view/devices/network/wireless.py:61
+msgid "Disconnected"
+msgstr "已切断"
+
+#: ../shell/view/devices/network/wireless.py:131
+msgid "Channel"
+msgstr "频道"
+
+#: ../shell/view/frame/zoomtoolbar.py:42
+msgid "Neighborhood"
+msgstr "邻居"
+
+#: ../shell/view/frame/zoomtoolbar.py:54
+msgid "Group"
+msgstr "组"
+
+#: ../shell/view/frame/zoomtoolbar.py:66
+msgid "Home"
+msgstr "家"
+
+#: ../shell/view/frame/zoomtoolbar.py:78
+msgid "Activity"
+msgstr "活动"
+
+#: ../lib/sugar/activity/activity.py:115
+msgid "Share with:"
+msgstr "共享:"
+
+#: ../lib/sugar/activity/activity.py:117
+msgid "Private"
+msgstr "私人"
+
+#: ../lib/sugar/activity/activity.py:118
+msgid "My Neighborhood"
+msgstr "我的邻居"
+
+#: ../lib/sugar/activity/activity.py:126
+msgid "Keep"
+msgstr "保持"
+
+#: ../lib/sugar/activity/activity.py:245
+msgid "Undo"
+msgstr "撤销"
+
+#: ../lib/sugar/activity/activity.py:250
+msgid "Redo"
+msgstr "重复"
+
+#: ../lib/sugar/activity/activity.py:260
+msgid "Copy"
+msgstr "复制"
+
+#: ../lib/sugar/activity/activity.py:265
+msgid "Paste"
+msgstr "粘贴"
+
+#: ../lib/sugar/activity/activity.py:454
+#, python-format
+msgid "%s Activity"
+msgstr "%s 的活动"
+
+#: ../lib/sugar/activity/activity.py:824
+msgid "Keep error"
+msgstr "保持错误"
+
+#: ../lib/sugar/activity/activity.py:825
+msgid "Keep error: all changes will be lost"
+msgstr "保持错误:所有改动都将撤销"
+
+#: ../lib/sugar/activity/activity.py:828
+msgid "Don't stop"
+msgstr "不停止"
+
+#: ../lib/sugar/activity/activity.py:831
+msgid "Stop anyway"
+msgstr "停止吧"
+
+#: ../lib/sugar/graphics/alert.py:164 ../lib/sugar/graphics/alert.py:206
+msgid "Cancel"
+msgstr "取消"
+
+#: ../lib/sugar/graphics/alert.py:168
+msgid "Ok"
+msgstr "确定"
+
+#: ../lib/sugar/graphics/alert.py:216
+msgid "Continue"
+msgstr "继续"
+
+#: ../lib/sugar/graphics/alert.py:244
+msgid "OK"
+msgstr "确定"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d year"
+msgstr "%d 年"
+
+#: ../lib/sugar/graphics/objectchooser.py:175
+#, python-format
+msgid "%d years"
+msgstr "%d 年"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d month"
+msgstr "%d 月"
+
+#: ../lib/sugar/graphics/objectchooser.py:176
+#, python-format
+msgid "%d months"
+msgstr "%d 月"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d week"
+msgstr "%d 星期"
+
+#: ../lib/sugar/graphics/objectchooser.py:177
+#, python-format
+msgid "%d weeks"
+msgstr "%d 星期"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d day"
+msgstr "%d 天"
+
+#: ../lib/sugar/graphics/objectchooser.py:178
+#, python-format
+msgid "%d days"
+msgstr "%d 天"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hour"
+msgstr "%d 小时"
+
+#: ../lib/sugar/graphics/objectchooser.py:179
+#, python-format
+msgid "%d hours"
+msgstr "%d 小时"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minute"
+msgstr "%d 分钟"
+
+#: ../lib/sugar/graphics/objectchooser.py:180
+#, python-format
+msgid "%d minutes"
+msgstr "%d 分钟"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d second"
+msgstr "%d 秒"
+
+#: ../lib/sugar/graphics/objectchooser.py:181
+#, python-format
+msgid "%d seconds"
+msgstr "%d 秒"
+
+#: ../lib/sugar/graphics/objectchooser.py:191
+msgid " and "
+msgstr "和"
+
+#: ../lib/sugar/graphics/objectchooser.py:193
+msgid ", "
+msgstr ","
+
+# 如何翻译sugar?
+#: ../shell/controlpanel/control.py:213
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "你需要重新启动系统, 让改变生效.\n"
+
+#: ../shell/controlpanel/control.py:267
+msgid "Error in specified color modifiers."
+msgstr "给定变化色时发生错误"
+
+#: ../shell/controlpanel/control.py:270
+msgid "Error in specified colors."
+msgstr "给定颜色时发生错误"
+
+#: ../shell/controlpanel/control.py:307
+msgid "off"
+msgstr "关闭"
+
+#: ../shell/controlpanel/control.py:309
+msgid "on"
+msgstr "开启"
+
+#: ../shell/controlpanel/control.py:310
+msgid "State is unknown."
+msgstr "未知状态"
+
+#: ../shell/controlpanel/control.py:332
+msgid "Error in specified radio argument use on/off."
+msgstr "给定无线信号开/关时发生错误"
+
+#: ../shell/controlpanel/control.py:336
+msgid "Permission denied. You need to be root to run this method."
+msgstr "权限不足. 你需要管理员权限来执行."
+
+#: ../shell/controlpanel/control.py:366
+msgid "Error in reading timezone"
+msgstr "阅读时区资料时发生错误"
+
+#: ../shell/controlpanel/control.py:397
+#, python-format
+msgid "Error copying timezone (from %s): %s"
+msgstr "从 %s 复制时区资料时发生错误: %s"
+
+#: ../shell/controlpanel/control.py:402
+#, python-format
+msgid "Changing permission of timezone: %s"
+msgstr "改变时区设置的权限: %s"
+
+#: ../shell/controlpanel/control.py:412
+msgid "Error timezone does not exist."
+msgstr "错误, 时区资料不存在."
+
+#: ../shell/controlpanel/control.py:417 ../shell/controlpanel/control.py:436
+#, python-format
+msgid "Could not access %s. Create standard settings."
+msgstr "不能访问%s. 创建标准设置."
+
+#: ../shell/controlpanel/control.py:463
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "无法确定代码为 %s 的语言"
+
+#: ../shell/controlpanel/control.py:473
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "对不起,我不会说 '%s'"
+
+#: ../shell/view/devices/network/mesh.py:105
+msgid "Connected to a School Mesh Portal"
+msgstr "已连接到一个学校网状网络门户"
+
+#: ../shell/view/devices/network/mesh.py:107
+msgid "Looking for a School Mesh Portal..."
+msgstr "寻找学校网状网络门户中..."
+
+#: ../shell/view/devices/network/mesh.py:110
+msgid "Connected to an XO Mesh Portal"
+msgstr "已连接到一个XO网状网络门户"
+
+#: ../shell/view/devices/network/mesh.py:112
+msgid "Looking for an XO Mesh Portal..."
+msgstr "寻找XO网状网络门户中..."
+
+#: ../shell/view/devices/network/mesh.py:115
+msgid "Connected to a Simple Mesh"
+msgstr "已连接到一个简单网状网络"
+
+#: ../shell/view/devices/network/mesh.py:117
+msgid "Starting a Simple Mesh"
+msgstr "创建一个简单网状网络"
+
+#: ../shell/view/devices/network/mesh.py:124
+msgid "Unknown Mesh"
+msgstr "未知网状网络"
+
+#: ../shell/view/home/HomeBox.py:175 ../shell/view/home/HomeBox.py:216
+msgid "About this XO"
+msgstr ""
+
+#: ../shell/view/home/HomeBox.py:222
+msgid "Not available"
+msgstr ""
diff --git a/shell/po/zh_TW.po b/shell/po/zh_TW.po
new file mode 100644
index 0000000..1a2b113
--- /dev/null
+++ b/shell/po/zh_TW.po
@@ -0,0 +1,1543 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: Sugar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-11 00:32-0500\n"
+"PO-Revision-Date: 2010-03-28 16:09+0200\n"
+"Last-Translator: Yuan Chao <yuanchao@gmail.com>\n"
+"Language-Team: Yuan CHAO <yuanchao@gmail.com>\n"
+"Language: zh_TW\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"
+"X-Generator: Pootle 2.0.3\n"
+
+#: ../extensions/cpsection/aboutme/__init__.py:24
+msgid "About Me"
+msgstr "關於我"
+
+#: ../extensions/cpsection/aboutme/model.py:43
+msgid "You must enter a name."
+msgstr "請輸入姓名"
+
+#: ../extensions/cpsection/aboutme/model.py:68
+#, python-format
+msgid "stroke: color=%s hue=%s"
+msgstr "畫筆: 顏色=%s 色澤明暗=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:71
+#, python-format
+msgid "stroke: %s"
+msgstr "畫筆: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:73
+#, python-format
+msgid "fill: color=%s hue=%s"
+msgstr "填滿: 顏色=%s 色澤明暗=%s"
+
+#: ../extensions/cpsection/aboutme/model.py:75
+#, python-format
+msgid "fill: %s"
+msgstr "填滿: %s"
+
+#: ../extensions/cpsection/aboutme/model.py:86
+msgid "Error in specified color modifiers."
+msgstr "指定增修顏色時發生錯誤"
+
+#: ../extensions/cpsection/aboutme/model.py:89
+msgid "Error in specified colors."
+msgstr "指定顏色時發生錯誤"
+
+#: ../extensions/cpsection/aboutme/view.py:94 ../src/jarabe/intro/window.py:93
+msgid "Name:"
+msgstr "姓名:"
+
+#: ../extensions/cpsection/aboutme/view.py:128
+msgid "Click to change your color:"
+msgstr "點選改變顏色"
+
+#: ../extensions/cpsection/aboutcomputer/__init__.py:21
+msgid "About my Computer"
+msgstr "我的電腦"
+
+#: ../extensions/cpsection/aboutcomputer/model.py:28
+msgid "Not available"
+msgstr "不存在"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:60
+msgid "Identity"
+msgstr "身份識別"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:69
+msgid "Serial Number:"
+msgstr "序號"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:91
+msgid "Software"
+msgstr "軟體"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:100
+msgid "Build:"
+msgstr "建立:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:115
+msgid "Sugar:"
+msgstr "Sugar:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:131
+msgid "Firmware:"
+msgstr "韌體:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:146
+msgid "Wireless Firmware:"
+msgstr "無線網路韌體:"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:169
+msgid "Copyright and License"
+msgstr "版權與授權資料"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:184
+msgid ""
+"Sugar is the graphical user interface that you are looking at. Sugar is free "
+"software, covered by the GNU General Public License, and you are welcome to "
+"change it and/or distribute copies of it under certain conditions described "
+"therein."
+msgstr "Sugar 是您目前所看到的使用者界面,Sugar 是一個自由軟體,以 GNU 的 GPL 授權。歡迎您依據授權條例修改與散佈本軟體。"
+
+#: ../extensions/cpsection/aboutcomputer/view.py:196
+msgid "Full license:"
+msgstr "完整授權條例:"
+
+#: ../extensions/cpsection/datetime/__init__.py:21
+msgid "Date & Time"
+msgstr "日期與時間"
+
+#: ../extensions/cpsection/datetime/model.py:87
+msgid "Error timezone does not exist."
+msgstr "錯誤,時區資料不存在."
+
+#: ../extensions/cpsection/datetime/view.py:68 ../data/sugar.schemas.in.h:33
+msgid "Timezone"
+msgstr "時區"
+
+#: ../extensions/cpsection/frame/__init__.py:21
+msgid "Frame"
+msgstr "畫面"
+
+#: ../extensions/cpsection/frame/model.py:38
+#: ../extensions/cpsection/frame/model.py:60
+msgid "Value must be an integer."
+msgstr "指定數值必需為整數"
+
+#: ../extensions/cpsection/frame/view.py:26
+msgid "never"
+msgstr "永不"
+
+#: ../extensions/cpsection/frame/view.py:27
+msgid "instantaneous"
+msgstr "即時"
+
+#: ../extensions/cpsection/frame/view.py:28
+#, python-format
+msgid "%s seconds"
+msgstr "%s秒"
+
+#: ../extensions/cpsection/frame/view.py:52
+msgid "Activation Delay"
+msgstr "啟用延遲"
+
+#: ../extensions/cpsection/frame/view.py:76
+msgid "Corner"
+msgstr "角落"
+
+#: ../extensions/cpsection/frame/view.py:111
+msgid "Edge"
+msgstr "邊緣"
+
+#: ../extensions/cpsection/keyboard/__init__.py:21
+#: ../extensions/cpsection/keyboard/view.py:31
+msgid "Keyboard"
+msgstr "鍵盤"
+
+#: ../extensions/cpsection/keyboard/view.py:189
+msgid "Keyboard Model"
+msgstr "鍵盤型式"
+
+#: ../extensions/cpsection/keyboard/view.py:248
+msgid "Key(s) to change layout"
+msgstr "按鍵改變樣式"
+
+#: ../extensions/cpsection/keyboard/view.py:318
+msgid "Keyboard Layout(s)"
+msgstr "鍵盤樣式"
+
+#: ../extensions/cpsection/language/__init__.py:21
+#: ../extensions/cpsection/language/view.py:33
+msgid "Language"
+msgstr "語言"
+
+#: ../extensions/cpsection/language/model.py:28
+msgid "Could not access ~/.i18n. Create standard settings."
+msgstr "無法讀取 ~/.i18n。 建立標準設定。"
+
+#: ../extensions/cpsection/language/model.py:124
+#, python-format
+msgid "Language for code=%s could not be determined."
+msgstr "語系編碼 %s 無法判定"
+
+#: ../extensions/cpsection/language/model.py:144
+#, python-format
+msgid "Sorry I do not speak '%s'."
+msgstr "抱歉我不會說'%s'."
+
+#: ../extensions/cpsection/language/view.py:56
+msgid ""
+"Add languages in the order you prefer. If a translation is not available, "
+"the next in the list will be used."
+msgstr "請依序加入你使用的語言。如果優先選定的語言缺少翻譯,則使用次優先的語言翻譯。"
+
+#: ../extensions/cpsection/modemconfiguration/__init__.py:21
+msgid "Modem Configuration"
+msgstr "數據機設定"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:90
+msgid "Username:"
+msgstr "使用者帳號:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:101
+msgid "Password:"
+msgstr "密碼:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:112
+msgid "Number:"
+msgstr "撥接號碼:"
+
+#: ../extensions/cpsection/modemconfiguration/view.py:123
+msgid "APN:"
+msgstr "接取點名稱(APN):"
+
+#: ../extensions/cpsection/network/__init__.py:21
+#: ../extensions/cpsection/network/view.py:28
+msgid "Network"
+msgstr "網路"
+
+#: ../extensions/cpsection/network/model.py:79
+msgid "State is unknown."
+msgstr "未知狀態"
+
+#: ../extensions/cpsection/network/model.py:105
+msgid "Error in specified radio argument use on/off."
+msgstr "錯誤的無線網路信號開關設定,請指定on/off。"
+
+#: ../extensions/cpsection/network/model.py:137
+msgid "Error in specified argument use 0/1."
+msgstr "無線網路信號開關只能設為 0/1。"
+
+#: ../extensions/cpsection/network/view.py:59
+msgid "Wireless"
+msgstr "無線網路"
+
+#: ../extensions/cpsection/network/view.py:67
+msgid "Turn off the wireless radio to save battery life"
+msgstr "關閉無線網路信號來增加電池使用時間"
+
+#: ../extensions/cpsection/network/view.py:80
+msgid "Radio"
+msgstr "無線網路信號"
+
+#: ../extensions/cpsection/network/view.py:96
+msgid "Discard network history if you have trouble connecting to the network"
+msgstr "如果您遇到連線上的問題,請嘗試清除舊的網路歷史資料"
+
+#: ../extensions/cpsection/network/view.py:105
+msgid "Discard network history"
+msgstr "清除舊的網路歷史資料"
+
+#: ../extensions/cpsection/network/view.py:118
+msgid "Collaboration"
+msgstr "協同合作"
+
+#: ../extensions/cpsection/network/view.py:126
+msgid ""
+"The server is the equivalent of what room you are in; people on the same "
+"server will be able to see each other, even when they aren't on the same "
+"network."
+msgstr "伺服器就等同於你所在的房間,在同一個伺服器上的使用者可以互相看見彼此,即使是實際上他們不在同一個網路中。"
+
+#: ../extensions/cpsection/network/view.py:136
+msgid "Server:"
+msgstr "伺服器"
+
+#: ../extensions/cpsection/power/__init__.py:21
+msgid "Power"
+msgstr "電源"
+
+#: ../extensions/cpsection/power/model.py:54
+msgid "Error in automatic pm argument, use on/off."
+msgstr "自動省電管理開關發生錯誤"
+
+#: ../extensions/cpsection/power/model.py:81
+msgid "Error in extreme pm argument, use on/off."
+msgstr "極度省電管理開關發生錯誤"
+
+#: ../extensions/cpsection/power/view.py:47
+msgid "Power management"
+msgstr "電源管理"
+
+#: ../extensions/cpsection/power/view.py:57
+msgid "Automatic power management (increases battery life)"
+msgstr "自動電源管理模式 (增加電池使用時間)"
+
+#: ../extensions/cpsection/power/view.py:85
+msgid ""
+"Extreme power management (disableswireless radio, increases battery life)"
+msgstr "積極電源管理模式 (關閉無線網路,增加電池使用時間)"
+
+#: ../extensions/cpsection/updater/__init__.py:21
+msgid "Software update"
+msgstr "軟體更新"
+
+#: ../extensions/cpsection/updater/view.py:63
+msgid ""
+"Software updates correct errors, eliminate security vulnerabilities, and "
+"provide new features."
+msgstr "軟體更新會修正錯誤,消除安全上的弱點,以及增加新的功能。"
+
+#: ../extensions/cpsection/updater/view.py:125
+#, python-format
+msgid "Checking %s..."
+msgstr "檢查 %s 中…"
+
+#: ../extensions/cpsection/updater/view.py:127
+#, python-format
+msgid "Downloading %s..."
+msgstr "下載 %s 中…"
+
+#: ../extensions/cpsection/updater/view.py:129
+#, python-format
+msgid "Updating %s..."
+msgstr "更新 %s 中…"
+
+#: ../extensions/cpsection/updater/view.py:139
+msgid "Your software is up-to-date"
+msgstr "您的軟體已經是最新版本"
+
+#: ../extensions/cpsection/updater/view.py:141
+#, python-format
+msgid "You can install %s update"
+msgid_plural "You can install %s updates"
+msgstr[0] "您可以安裝 %s 個更新"
+
+#: ../extensions/cpsection/updater/view.py:159
+msgid "Checking for updates..."
+msgstr "檢查更新中…"
+
+#: ../extensions/cpsection/updater/view.py:164
+msgid "Installing updates..."
+msgstr "安裝更新中…"
+
+#: ../extensions/cpsection/updater/view.py:172
+#, python-format
+msgid "%s update was installed"
+msgid_plural "%s updates were installed"
+msgstr[0] "已安裝 %s 個更新"
+
+#: ../extensions/cpsection/updater/view.py:253
+msgid "Install selected"
+msgstr "安裝選用的"
+
+#: ../extensions/cpsection/updater/view.py:274
+#, python-format
+msgid "Download size: %s"
+msgstr "下載檔案大小:%s"
+
+#: ../extensions/cpsection/updater/view.py:362
+#, python-format
+msgid "From version %(current)d to %(new)s (Size: %(size)s)"
+msgstr "由版本 %(current)d 更新至 %(new)s (大小: %(size)s)"
+
+#. TRANS: download size is 0
+#: ../extensions/cpsection/updater/view.py:382
+msgid "None"
+msgstr "無"
+
+#. TRANS: download size of very small updates
+#: ../extensions/cpsection/updater/view.py:385
+msgid "1 KB"
+msgstr "1 KB"
+
+#. TRANS: download size of small updates, e.g. '250 KB'
+#: ../extensions/cpsection/updater/view.py:388
+#, python-format
+msgid "%.0f KB"
+msgstr "%.0f KB"
+
+#. TRANS: download size of updates, e.g. '2.3 MB'
+#: ../extensions/cpsection/updater/view.py:391
+#, python-format
+msgid "%.1f MB"
+msgstr "%.1f MB"
+
+#: ../extensions/deviceicon/battery.py:58
+msgid "My Battery"
+msgstr "我的電池狀態"
+
+#: ../extensions/deviceicon/battery.py:137
+msgid "Removed"
+msgstr "移除"
+
+#: ../extensions/deviceicon/battery.py:140
+msgid "Charging"
+msgstr "充電中"
+
+#: ../extensions/deviceicon/battery.py:143
+msgid "Very little power remaining"
+msgstr "電池電源即將用完"
+
+#: ../extensions/deviceicon/battery.py:149
+#, python-format
+msgid "%(hour)d:%(min).2d remaining"
+msgstr "剩餘 %(hour)d:%(min).2d"
+
+#: ../extensions/deviceicon/battery.py:152
+msgid "Charged"
+msgstr "充電完成"
+
+#: ../extensions/deviceicon/network.py:49
+#, python-format
+msgid "IP address: %s"
+msgstr "網路地址: %s"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:111
+msgid "Disconnect..."
+msgstr "切斷連線…"
+
+#: ../extensions/deviceicon/network.py:116
+msgid "Create new wireless network"
+msgstr "新增無線網路"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#: ../extensions/deviceicon/network.py:122
+#: ../extensions/deviceicon/network.py:284
+#: ../src/jarabe/desktop/meshbox.py:248 ../src/jarabe/desktop/meshbox.py:537
+msgid "Connecting..."
+msgstr "連線中…"
+
+# TODO: show the channel number
+#: ../extensions/deviceicon/network.py:126
+#: ../extensions/deviceicon/network.py:198
+#: ../extensions/deviceicon/network.py:288
+#: ../src/jarabe/desktop/meshbox.py:254 ../src/jarabe/desktop/meshbox.py:543
+msgid "Connected"
+msgstr "已連線"
+
+#: ../extensions/deviceicon/network.py:158
+msgid "Channel"
+msgstr "頻道"
+
+#: ../extensions/deviceicon/network.py:173
+msgid "Wired Network"
+msgstr "有線網路"
+
+#: ../extensions/deviceicon/network.py:201
+msgid "Speed"
+msgstr "速度"
+
+#: ../extensions/deviceicon/network.py:228
+msgid "Wireless modem"
+msgstr "無線網路數據機"
+
+#: ../extensions/deviceicon/network.py:276
+msgid "Please wait..."
+msgstr "請稍待…"
+
+#: ../extensions/deviceicon/network.py:279
+#: ../src/jarabe/desktop/meshbox.py:164 ../src/jarabe/desktop/meshbox.py:494
+msgid "Connect"
+msgstr "連線"
+
+#: ../extensions/deviceicon/network.py:280
+msgid "Disconnected"
+msgstr "已切斷"
+
+#: ../extensions/deviceicon/network.py:283
+#: ../src/jarabe/controlpanel/toolbar.py:115
+#: ../src/jarabe/desktop/homebox.py:68
+#: ../src/jarabe/frame/activitiestray.py:700
+#: ../src/jarabe/frame/activitiestray.py:799
+#: ../src/jarabe/frame/activitiestray.py:827
+msgid "Cancel"
+msgstr "取消"
+
+#: ../extensions/deviceicon/network.py:287
+#: ../src/jarabe/desktop/meshbox.py:168
+msgid "Disconnect"
+msgstr "切斷連線"
+
+#: ../extensions/deviceicon/network.py:530
+#, python-format
+msgid "%s's network"
+msgstr "%s 的網路"
+
+#: ../extensions/deviceicon/network.py:597
+#: ../extensions/deviceicon/network.py:656
+msgid "Mesh Network"
+msgstr "網狀網路"
+
+#: ../extensions/deviceicon/network.py:857
+#, python-format
+msgid "Data sent %d kb / received %d kb"
+msgstr "資料發送 %d kb / 接收 %d kb"
+
+#: ../extensions/deviceicon/network.py:868
+msgid "Connection time "
+msgstr "連線時間 "
+
+#: ../extensions/deviceicon/speaker.py:59
+msgid "My Speakers"
+msgstr "我的喇叭"
+
+#: ../extensions/deviceicon/speaker.py:133
+msgid "Unmute"
+msgstr "取消靜音"
+
+#: ../extensions/deviceicon/speaker.py:136
+msgid "Mute"
+msgstr "喇叭靜音"
+
+#: ../extensions/globalkey/screenshot.py:59
+msgid "Mesh"
+msgstr "網狀網路"
+
+#: ../extensions/globalkey/screenshot.py:61
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "Group"
+msgstr "我的群組"
+
+#: ../extensions/globalkey/screenshot.py:63
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "Home"
+msgstr "我的家"
+
+#: ../extensions/globalkey/screenshot.py:69
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "Activity"
+msgstr "活動"
+
+#: ../extensions/globalkey/screenshot.py:72
+msgid "Screenshot"
+msgstr "畫面抓圖"
+
+#: ../extensions/globalkey/screenshot.py:74
+#, python-format
+msgid "Screenshot of \"%s\""
+msgstr "%s 的畫面抓圖"
+
+#: ../data/sugar.schemas.in.h:1
+msgid ""
+"\"disabled\" to ask nick on initialization; \"system\" to reuse UNIX account "
+"long name."
+msgstr "點選「停用」將於啟動時詢問代號,點選「系統」則恢復使用 UNIX 名稱。"
+
+#: ../data/sugar.schemas.in.h:2
+msgid "Backup URL"
+msgstr "備份網址"
+
+#: ../data/sugar.schemas.in.h:3
+msgid ""
+"Color for the XO icon that is used throughout the desktop. The string is "
+"composed of the stroke color and fill color, format is that of rbg colors. "
+"Example: #AC32FF,#9A5200"
+msgstr "您選取的顏色將使用在整個桌面當中。顏色指定字串包含了筆畫顏色與填充顏色,格式為紅藍綠三原色的強度。例如: #AC32FF,#9A5200"
+
+#: ../data/sugar.schemas.in.h:4
+msgid "Corner Delay"
+msgstr "角落觸發延遲"
+
+#: ../data/sugar.schemas.in.h:5
+msgid "Default font face"
+msgstr "預設字型"
+
+#: ../data/sugar.schemas.in.h:6
+msgid "Default font size"
+msgstr "預設字體大小"
+
+#: ../data/sugar.schemas.in.h:7
+msgid "Default nick"
+msgstr "預設代號"
+
+#: ../data/sugar.schemas.in.h:8
+msgid "Delay for the activation of the frame using the corners."
+msgstr "當游標移到畫面四角時浮現邊框的延遲時間"
+
+#: ../data/sugar.schemas.in.h:9
+msgid "Delay for the activation of the frame using the edges."
+msgstr "當游標移到畫面邊緣時浮現邊框的延遲時間"
+
+#: ../data/sugar.schemas.in.h:10
+msgid "Edge Delay"
+msgstr "邊緣觸發延遲"
+
+#: ../data/sugar.schemas.in.h:11
+msgid "Favorites Layout"
+msgstr "偏好的顯示方式"
+
+#: ../data/sugar.schemas.in.h:12
+msgid "Favorites resume mode"
+msgstr "偏好的回復模式"
+
+#: ../data/sugar.schemas.in.h:13
+msgid "Font face that is used throughout the desktop."
+msgstr "預設字型將套用於整個桌面環境"
+
+#: ../data/sugar.schemas.in.h:14
+msgid "Font size that is used throughout the desktop."
+msgstr "預設字體大小將套用於整個桌面環境"
+
+#: ../data/sugar.schemas.in.h:15
+msgid ""
+"If TRUE, Sugar will make us searchable for the other users of the Jabber "
+"server."
+msgstr "選擇「是」的話,Sugar 將會讓其他 Jabber 伺服器的使用者可以搜尋到我們"
+
+#: ../data/sugar.schemas.in.h:16
+msgid "If TRUE, Sugar will show a \"Log out\" option."
+msgstr "選擇「是」的話,Sugar 將會顯示『登出』的選項"
+
+#: ../data/sugar.schemas.in.h:17
+msgid "Jabber Server"
+msgstr "Jabber 伺服器"
+
+#: ../data/sugar.schemas.in.h:18
+msgid "Keyboard layouts"
+msgstr "鍵盤排列"
+
+#: ../data/sugar.schemas.in.h:19
+msgid "Keyboard model"
+msgstr "鍵盤型號"
+
+#: ../data/sugar.schemas.in.h:20
+msgid "Keyboard options"
+msgstr "鍵盤選項"
+
+#: ../data/sugar.schemas.in.h:21
+msgid "Layout of the favorites view."
+msgstr "我的最愛顯示方式"
+
+#: ../data/sugar.schemas.in.h:22
+msgid ""
+"List of keyboard layouts. Each entry should be in the form layout(variant)"
+msgstr "鍵盤排列列表,每個項目應該在排列列表中"
+
+#: ../data/sugar.schemas.in.h:23
+msgid "List of keyboard options."
+msgstr "鍵盤排列列表"
+
+#: ../data/sugar.schemas.in.h:24
+msgid "Power Automatic"
+msgstr "自動省電模式"
+
+#: ../data/sugar.schemas.in.h:25
+msgid "Power Automatic."
+msgstr "自動省電模式。"
+
+#: ../data/sugar.schemas.in.h:26
+msgid "Power Extreme"
+msgstr "極度省電模式"
+
+#: ../data/sugar.schemas.in.h:27
+msgid "Power Extreme."
+msgstr "極度省電模式。"
+
+#: ../data/sugar.schemas.in.h:28
+msgid "Publish to Gadget"
+msgstr "發佈到小工具"
+
+#: ../data/sugar.schemas.in.h:29
+msgid "Setting for muting the sound device."
+msgstr "音效設備靜音設定。"
+
+#: ../data/sugar.schemas.in.h:30
+msgid "Show Log out"
+msgstr "顯示登出"
+
+#: ../data/sugar.schemas.in.h:31
+msgid "Sound Muted"
+msgstr "靜音"
+
+#: ../data/sugar.schemas.in.h:32
+msgid "The keyboard model to be used"
+msgstr "選用的鍵盤型式"
+
+#: ../data/sugar.schemas.in.h:34
+msgid "Timezone setting for the system."
+msgstr "系統的時區設定"
+
+#: ../data/sugar.schemas.in.h:35
+msgid "Url of the jabber server to use."
+msgstr "Jabber 伺服器的網址。"
+
+#: ../data/sugar.schemas.in.h:36
+msgid "Url where the backup is saved to."
+msgstr "備份主機的網址。"
+
+#: ../data/sugar.schemas.in.h:37
+msgid "User Color"
+msgstr "使用者顏色"
+
+#: ../data/sugar.schemas.in.h:38
+msgid "User Name"
+msgstr "使用者名稱"
+
+#: ../data/sugar.schemas.in.h:39
+msgid "User name that is used throughout the desktop."
+msgstr "使用者名稱將用於整個桌面上"
+
+#: ../data/sugar.schemas.in.h:40
+msgid "Volume Level"
+msgstr "音量"
+
+#: ../data/sugar.schemas.in.h:41
+msgid "Volume level for the sound device."
+msgstr "音效設備的音量"
+
+#: ../data/sugar.schemas.in.h:42
+msgid ""
+"When in resume mode, clicking on a favorite icon will cause the last entry "
+"for that activity to be resumed."
+msgstr "在回復模式下,點選偏好的圖示將回復該活動前一次的使用狀態"
+
+#: ../src/jarabe/controlpanel/cmd.py:28
+#, python-format
+msgid ""
+"sugar-control-panel: WARNING, found more than one option with the same name: "
+"%s module: %r"
+msgstr "Sugar控制台:警告,於模組 %r 中發現重複的選項名稱:%s"
+
+#: ../src/jarabe/controlpanel/cmd.py:30
+#, python-format
+msgid "sugar-control-panel: key=%s not an available option"
+msgstr "Sugar控制台: 鍵值=%s 並非可用的選項"
+
+#: ../src/jarabe/controlpanel/cmd.py:31
+#, python-format
+msgid "sugar-control-panel: %s"
+msgstr "Sugar控制台: %s"
+
+# TRANS: Translators, there's a empty line at the end of this string,
+# which must appear in the translated string (msgstr) as well.
+#. TRANS: Translators, there's a empty line at the end of this string,
+#. which must appear in the translated string (msgstr) as well.
+#: ../src/jarabe/controlpanel/cmd.py:37
+msgid ""
+"Usage: sugar-control-panel [ option ] key [ args ... ] \n"
+" Control for the sugar environment. \n"
+" Options: \n"
+" -h show this help message and exit \n"
+" -l list all the available options \n"
+" -h key show information about this key \n"
+" -g key get the current value of the key \n"
+" -s key set the current value for the key \n"
+" -c key clear the current value for the key \n"
+" "
+msgstr ""
+"用法: sugar-control-panel [ 選項 ] 鍵值 [ 參數 ... ] \n"
+" Sugar 環境設定工具. \n"
+" 選項: \n"
+" -h 顯示本說明文字並離開 \n"
+" -l 列出所有的選項 \n"
+" -h key 顯示本鍵值的說明 \n"
+" -g key 取得本件值的資料 \n"
+" -s key 設定本鍵值的資料 \n"
+" -c key 清除本鍵值的資料 \n"
+" "
+
+#: ../src/jarabe/controlpanel/cmd.py:50
+msgid "To apply your changes you have to restart sugar.\n"
+msgstr "需要重新啟動系統使變更生效.\n"
+
+#: ../src/jarabe/controlpanel/gui.py:281
+msgid "Warning"
+msgstr "警告"
+
+#: ../src/jarabe/controlpanel/gui.py:282
+#: ../src/jarabe/controlpanel/sectionview.py:42
+msgid "Changes require restart"
+msgstr "改變須要重新啟動才能生效"
+
+#: ../src/jarabe/controlpanel/gui.py:285
+msgid "Cancel changes"
+msgstr "取消改變"
+
+#: ../src/jarabe/controlpanel/gui.py:290 ../src/jarabe/desktop/homebox.py:70
+msgid "Later"
+msgstr "稍候"
+
+#: ../src/jarabe/controlpanel/gui.py:294
+msgid "Restart now"
+msgstr "馬上重新啟動"
+
+#: ../src/jarabe/controlpanel/toolbar.py:61 ../src/jarabe/intro/window.py:206
+msgid "Done"
+msgstr "完成"
+
+#: ../src/jarabe/controlpanel/toolbar.py:121
+#: ../src/jarabe/desktop/favoritesview.py:333
+msgid "Ok"
+msgstr "確定"
+
+#: ../src/jarabe/desktop/activitieslist.py:236
+#, python-format
+msgid "Version %s"
+msgstr "版本 %s"
+
+#: ../src/jarabe/desktop/activitieslist.py:357
+msgid "Confirm erase"
+msgstr "確認刪除"
+
+#: ../src/jarabe/desktop/activitieslist.py:359
+#, python-format
+msgid "Confirm erase: Do you want to permanently erase %s?"
+msgstr "確認刪除:您確定要永久地刪除 %s 嗎?"
+
+# self._stop_item = MenuItem(_('Stop download'), 'stock-close')
+# TODO: Implement stopping downloads
+# self._stop_item.connect('activate', self._stop_item_activate_cb)
+# self.append_menu_item(self._stop_item)
+#: ../src/jarabe/desktop/activitieslist.py:363
+#: ../src/jarabe/frame/clipboardmenu.py:63
+#: ../src/jarabe/view/viewsource.py:218
+msgid "Keep"
+msgstr "保存"
+
+#: ../src/jarabe/desktop/activitieslist.py:366
+#: ../src/jarabe/desktop/activitieslist.py:409
+#: ../src/jarabe/journal/journaltoolbox.py:360
+#: ../src/jarabe/journal/palettes.py:105
+msgid "Erase"
+msgstr "刪除"
+
+#: ../src/jarabe/desktop/activitieslist.py:430
+msgid "Remove favorite"
+msgstr "移除偏好活動"
+
+#: ../src/jarabe/desktop/activitieslist.py:434
+msgid "Make favorite"
+msgstr "指定偏好活動"
+
+# TRANS: label for the freeform layout in the favorites view
+#. TRANS: label for the freeform layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:116
+msgid "Freeform"
+msgstr "自由格式"
+
+# TRANS: label for the ring layout in the favorites view
+#. TRANS: label for the ring layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:198
+msgid "Ring"
+msgstr "活動環"
+
+# TRANS: label for the spiral layout in the favorites view
+#. TRANS: label for the spiral layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:337
+msgid "Spiral"
+msgstr "螺旋"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:404
+msgid "Box"
+msgstr "方型"
+
+# TRANS: label for the box layout in the favorites view
+#. TRANS: label for the box layout in the favorites view
+#: ../src/jarabe/desktop/favoriteslayout.py:445
+msgid "Triangle"
+msgstr "三角形"
+
+#: ../src/jarabe/desktop/favoritesview.py:324
+msgid "Registration Failed"
+msgstr "註冊失敗"
+
+#: ../src/jarabe/desktop/favoritesview.py:325
+#, python-format
+msgid "%s"
+msgstr "%s"
+
+#: ../src/jarabe/desktop/favoritesview.py:327
+msgid "Registration Successful"
+msgstr "註冊成功"
+
+#: ../src/jarabe/desktop/favoritesview.py:328
+msgid "You are now registered with your school server."
+msgstr "您已經成功註冊到校園主機"
+
+#: ../src/jarabe/desktop/favoritesview.py:630
+msgid "Register"
+msgstr "註冊"
+
+#: ../src/jarabe/desktop/homebox.py:63
+msgid "Software Update"
+msgstr "軟體更新"
+
+#: ../src/jarabe/desktop/homebox.py:64
+msgid "Update your activities to ensure compatibility with your new software"
+msgstr "更新您的活動來確保新軟體的相容性"
+
+#: ../src/jarabe/desktop/homebox.py:73
+msgid "Check now"
+msgstr "現在就檢查"
+
+#: ../src/jarabe/desktop/homebox.py:192
+msgid "List view"
+msgstr "檢視清單"
+
+#: ../src/jarabe/desktop/homebox.py:193
+msgid "<Ctrl>2"
+msgstr "<Ctrl>2"
+
+#: ../src/jarabe/desktop/homebox.py:255
+msgid "Favorites view"
+msgstr "偏好檢視"
+
+#: ../src/jarabe/desktop/homebox.py:256
+msgid "<Ctrl>1"
+msgstr "<Ctrl>1"
+
+#: ../src/jarabe/desktop/keydialog.py:135
+msgid "Key Type:"
+msgstr "金鑰類型:"
+
+#: ../src/jarabe/desktop/keydialog.py:155
+msgid "Authentication Type:"
+msgstr "認證類型:"
+
+#: ../src/jarabe/desktop/keydialog.py:220
+msgid "WPA & WPA2 Personal"
+msgstr "個人的 WPA & WPA2 加密"
+
+#: ../src/jarabe/desktop/keydialog.py:229
+msgid "Wireless Security:"
+msgstr "無線網路加密:"
+
+#: ../src/jarabe/desktop/meshbox.py:492
+#, python-format
+msgid "Mesh Network %d"
+msgstr "網狀網路 %d"
+
+# TRANS: Action label for resuming an activity.
+#. TRANS: Action label for resuming an activity.
+#: ../src/jarabe/desktop/meshbox.py:629
+#: ../src/jarabe/frame/activitiestray.py:735
+#: ../src/jarabe/journal/journaltoolbox.py:428
+#: ../src/jarabe/journal/palettes.py:65 ../src/jarabe/view/palettes.py:67
+msgid "Resume"
+msgstr "回復"
+
+#: ../src/jarabe/desktop/meshbox.py:634
+#: ../src/jarabe/frame/activitiestray.py:233
+msgid "Join"
+msgstr "加入"
+
+#: ../src/jarabe/desktop/schoolserver.py:103
+msgid "Cannot connect to the server."
+msgstr "無法連線到伺服器"
+
+#: ../src/jarabe/desktop/schoolserver.py:108
+msgid "The server could not complete the request."
+msgstr "伺服器無法完成查尋動作"
+
+#: ../src/jarabe/frame/activitiestray.py:238
+#: ../src/jarabe/frame/activitiestray.py:672
+msgid "Decline"
+msgstr "拒絕"
+
+#: ../src/jarabe/frame/activitiestray.py:624
+#, python-format
+msgid "%dB"
+msgstr "%dB"
+
+#: ../src/jarabe/frame/activitiestray.py:626
+#, python-format
+msgid "%dKB"
+msgstr "%dKB"
+
+#: ../src/jarabe/frame/activitiestray.py:628
+#, python-format
+msgid "%dMB"
+msgstr "%dMB"
+
+#: ../src/jarabe/frame/activitiestray.py:645
+#, python-format
+msgid "%s of %s"
+msgstr "%s 之 %s"
+
+#: ../src/jarabe/frame/activitiestray.py:657
+#, python-format
+msgid "Transfer from %r"
+msgstr "傳送自 %r"
+
+#: ../src/jarabe/frame/activitiestray.py:667
+msgid "Accept"
+msgstr "接受"
+
+#: ../src/jarabe/frame/activitiestray.py:690
+#: ../src/jarabe/frame/activitiestray.py:817
+#, python-format
+msgid "%s (%s)"
+msgstr "%s (%s)"
+
+#: ../src/jarabe/frame/activitiestray.py:724
+#: ../src/jarabe/frame/activitiestray.py:852
+msgid "Dismiss"
+msgstr "拒絕"
+
+#: ../src/jarabe/frame/activitiestray.py:787
+#, python-format
+msgid "Transfer to %r"
+msgstr "傳送給 %r"
+
+#: ../src/jarabe/frame/clipboardmenu.py:53 ../src/jarabe/view/palettes.py:221
+msgid "Remove"
+msgstr "移除"
+
+#: ../src/jarabe/frame/clipboardmenu.py:58
+#: ../src/jarabe/frame/clipboardmenu.py:81
+msgid "Open"
+msgstr "開啟"
+
+#: ../src/jarabe/frame/clipboardmenu.py:86
+msgid "Open with"
+msgstr "開啟使用"
+
+#: ../src/jarabe/frame/clipboardobject.py:49
+#, python-format
+msgid "%s clipping"
+msgstr "%s 裁剪"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "Neighborhood"
+msgstr "我的鄰居"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:37
+msgid "F1"
+msgstr "F1"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:39
+msgid "F2"
+msgstr "F2"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:41
+msgid "F3"
+msgstr "F3"
+
+#: ../src/jarabe/frame/zoomtoolbar.py:43
+msgid "F4"
+msgstr "F4"
+
+#: ../src/jarabe/intro/window.py:128
+msgid "Click to change color:"
+msgstr "點選改變顏色:"
+
+#: ../src/jarabe/intro/window.py:192 ../src/jarabe/journal/detailview.py:103
+msgid "Back"
+msgstr "上一步"
+
+#: ../src/jarabe/intro/window.py:209
+msgid "Next"
+msgstr "下一步"
+
+#: ../src/jarabe/journal/expandedentry.py:152
+#: ../src/jarabe/journal/palettes.py:59
+msgid "Untitled"
+msgstr "未命名"
+
+#: ../src/jarabe/journal/expandedentry.py:243
+msgid "No preview"
+msgstr "沒有預覽"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+#, python-format
+msgid "Kind: %s"
+msgstr "類別: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:262
+msgid "Unknown"
+msgstr "未知"
+
+#: ../src/jarabe/journal/expandedentry.py:263
+#, python-format
+msgid "Date: %s"
+msgstr "日期: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:264
+#, python-format
+msgid "Size: %s"
+msgstr "大小: %s"
+
+#: ../src/jarabe/journal/expandedentry.py:286 ../src/jarabe/journal/misc.py:93
+msgid "No date"
+msgstr "無日期"
+
+#: ../src/jarabe/journal/expandedentry.py:293
+msgid "Participants:"
+msgstr "參與者"
+
+#: ../src/jarabe/journal/expandedentry.py:316
+msgid "Description:"
+msgstr "說明:"
+
+#: ../src/jarabe/journal/expandedentry.py:341
+msgid "Tags:"
+msgstr "標籤:"
+
+#: ../src/jarabe/journal/journalactivity.py:108
+#: ../src/jarabe/journal/volumestoolbar.py:47
+msgid "Journal"
+msgstr "日誌"
+
+#: ../src/jarabe/journal/journaltoolbox.py:67
+msgid "Search"
+msgstr "搜尋"
+
+#: ../src/jarabe/journal/journaltoolbox.py:126
+msgid "Anytime"
+msgstr "任何時間"
+
+#: ../src/jarabe/journal/journaltoolbox.py:128
+msgid "Today"
+msgstr "今天"
+
+#: ../src/jarabe/journal/journaltoolbox.py:130
+msgid "Since yesterday"
+msgstr "一天內"
+
+# TRANS: Filter entries modified during the last 7 days.
+#. TRANS: Filter entries modified during the last 7 days.
+#: ../src/jarabe/journal/journaltoolbox.py:132
+msgid "Past week"
+msgstr "一週內"
+
+# TRANS: Filter entries modified during the last 30 days.
+#. TRANS: Filter entries modified during the last 30 days.
+#: ../src/jarabe/journal/journaltoolbox.py:134
+msgid "Past month"
+msgstr "一個月內"
+
+# TRANS: Filter entries modified during the last 356 days.
+#. TRANS: Filter entries modified during the last 356 days.
+#: ../src/jarabe/journal/journaltoolbox.py:136
+msgid "Past year"
+msgstr "一年內"
+
+#: ../src/jarabe/journal/journaltoolbox.py:143
+msgid "Anyone"
+msgstr "任何人"
+
+#: ../src/jarabe/journal/journaltoolbox.py:145
+msgid "My friends"
+msgstr "我的好友"
+
+#: ../src/jarabe/journal/journaltoolbox.py:146
+msgid "My class"
+msgstr "我的類別"
+
+# TRANS: Item in a combo box that filters by entry type.
+#: ../src/jarabe/journal/journaltoolbox.py:274
+msgid "Anything"
+msgstr "所有類別"
+
+# TODO: Add "Start with" menu item
+#: ../src/jarabe/journal/journaltoolbox.py:350
+#: ../src/jarabe/journal/palettes.py:83
+msgid "Copy"
+msgstr "複製"
+
+# TRANS: Action label for starting an entry.
+#. TRANS: Action label for starting an entry.
+#: ../src/jarabe/journal/journaltoolbox.py:431
+#: ../src/jarabe/journal/palettes.py:68
+msgid "Start"
+msgstr "啟動"
+
+#: ../src/jarabe/journal/listview.py:373
+msgid "Your Journal is empty"
+msgstr "空白的日誌內容"
+
+#: ../src/jarabe/journal/listview.py:375
+msgid "No matching entries"
+msgstr "沒有相符的紀錄"
+
+#: ../src/jarabe/journal/listview.py:386
+msgid "Clear search"
+msgstr "清除搜尋項目"
+
+#: ../src/jarabe/journal/modalalert.py:63
+msgid "Your Journal is full"
+msgstr "日誌空間已滿"
+
+#: ../src/jarabe/journal/modalalert.py:67
+msgid "Please delete some old Journal entries to make space for new ones."
+msgstr "請刪除一些舊的日誌內容來騰出空間給新的日誌"
+
+#: ../src/jarabe/journal/modalalert.py:79
+msgid "Show Journal"
+msgstr "顯示日誌"
+
+#: ../src/jarabe/journal/objectchooser.py:146
+msgid "Choose an object"
+msgstr "選擇物件"
+
+#: ../src/jarabe/journal/objectchooser.py:151
+#: ../src/jarabe/view/viewsource.py:308
+msgid "Close"
+msgstr "關閉"
+
+#: ../src/jarabe/journal/palettes.py:66
+msgid "Resume with"
+msgstr "回復活動"
+
+#: ../src/jarabe/journal/palettes.py:69
+msgid "Start with"
+msgstr "開始活動"
+
+#: ../src/jarabe/journal/palettes.py:91
+msgid "Send to"
+msgstr "傳送給"
+
+#: ../src/jarabe/journal/palettes.py:100
+msgid "View Details"
+msgstr "檢視詳細內容"
+
+#: ../src/jarabe/journal/palettes.py:178
+msgid "No friends present"
+msgstr "沒有好友上線"
+
+#: ../src/jarabe/journal/palettes.py:183
+msgid "No valid connection found"
+msgstr "找不到有效的網路連線"
+
+#: ../src/jarabe/journal/palettes.py:211
+msgid "No activity to resume entry"
+msgstr "找不到可以回復的活動"
+
+#: ../src/jarabe/journal/palettes.py:213
+msgid "No activity to start entry"
+msgstr "找不到可以開始的活動"
+
+#: ../src/jarabe/view/buddymenu.py:62
+msgid "Remove friend"
+msgstr "移除好友"
+
+#: ../src/jarabe/view/buddymenu.py:65
+msgid "Make friend"
+msgstr "結交好友"
+
+#: ../src/jarabe/view/buddymenu.py:82
+msgid "Shutdown"
+msgstr "關機"
+
+#: ../src/jarabe/view/buddymenu.py:90
+msgid "Logout"
+msgstr "顯示方式"
+
+#: ../src/jarabe/view/buddymenu.py:95
+msgid "My Settings"
+msgstr "我的設定"
+
+#: ../src/jarabe/view/buddymenu.py:130
+#, python-format
+msgid "Invite to %s"
+msgstr "邀請 %s"
+
+#: ../src/jarabe/view/palettes.py:45
+msgid "Starting..."
+msgstr "啟動中…"
+
+#. TODO: share-with, keep
+#: ../src/jarabe/view/palettes.py:74
+msgid "View Source"
+msgstr "檢視原始碼"
+
+#: ../src/jarabe/view/palettes.py:85
+msgid "Stop"
+msgstr "停止"
+
+#: ../src/jarabe/view/palettes.py:125
+msgid "Start new"
+msgstr "建立新的"
+
+#: ../src/jarabe/view/palettes.py:174
+msgid "Show contents"
+msgstr "顯示內容"
+
+#: ../src/jarabe/view/palettes.py:196 ../src/jarabe/view/palettes.py:246
+#, python-format
+msgid "%(free_space)d MB Free"
+msgstr "剩餘 %(free_space)d MB 空間"
+
+#: ../src/jarabe/view/viewsource.py:208
+msgid "Instance Source"
+msgstr "範例原始碼"
+
+#: ../src/jarabe/view/viewsource.py:233
+msgid "Source"
+msgstr "原始碼"
+
+#: ../src/jarabe/view/viewsource.py:292
+msgid "Activity Bundle Source"
+msgstr "預裝活動原始碼"
+
+#: ../src/jarabe/view/viewsource.py:299
+#, python-format
+msgid "View source: %r"
+msgstr "查看原始碼: %r"
+
+#~ msgid "Title"
+#~ msgstr "標題"
+
+#~ msgid "Version"
+#~ msgstr "版本"
+
+#~ msgid "Date"
+#~ msgstr "日期"
+
+#~ msgid "Cannot obtain data needed for registration."
+#~ msgstr "無法取得註冊所需的資料"
+
+#~ msgid "Unmount"
+#~ msgstr "退出磁碟"
+
+#~ msgid "Restart"
+#~ msgstr "重新啟動"
+
+#~ msgid ""
+#~ "© 2008 One Laptop per Child Association Inc; Red Hat Inc; and Contributors."
+#~ msgstr "© 2008 每童一機 公司; 紅帽 公司; 以及其他的貢獻者"
+
+#~ msgid "Document"
+#~ msgstr "文件"
+
+#~ msgid "Resume by default"
+#~ msgstr "預設回復"
+
+#~ msgid "Encryption Type:"
+#~ msgstr "加密類型:"
+
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#~ msgid "Disconnecting..."
+#~ msgstr "切斷連線中…"
+
+#~ msgid "About my XO"
+#~ msgstr "關於我的XO"
+
+#~ msgid "Connected to a School Mesh Portal"
+#~ msgstr "已連接到校園網狀網入口"
+
+#~ msgid "Looking for a School Mesh Portal..."
+#~ msgstr "搜尋校園網狀網路中..."
+
+#~ msgid "Connected to an XO Mesh Portal"
+#~ msgstr "已連接到XO網狀網入口"
+
+#~ msgid "Looking for an XO Mesh Portal..."
+#~ msgstr "搜尋XO網狀網路中..."
+
+#~ msgid "Connected to a Simple Mesh"
+#~ msgstr "已連接上簡易網狀網路"
+
+#~ msgid "Starting a Simple Mesh"
+#~ msgstr "建立簡易網狀網路"
+
+#~ msgid "Unknown Mesh"
+#~ msgstr "未知網狀網路"
+
+#~ msgid "Settings"
+#~ msgstr "設定"
+
+#, python-format
+#~ msgid "Clipboard object: %s."
+#~ msgstr "剪貼簿物件: %s."
+
+#~ msgid "You must enter a server."
+#~ msgstr "請指定伺服器"
+
+#~ msgid "Control Panel"
+#~ msgstr "控制台"
+
+#~ msgid "<Ctrl>R"
+#~ msgstr "<Ctrl>R"
+
+#~ msgid "off"
+#~ msgstr "關閉"
+
+#~ msgid "on"
+#~ msgstr "開啟"
+
+#~ msgid "Permission denied. You need to be root to run this method."
+#~ msgstr "權限不足, 需要有系統管理員權限才可以執行此功能。"
+
+#~ msgid "Error in reading timezone"
+#~ msgstr "讀取時區資料時發生錯誤"
+
+#, python-format
+#~ msgid "Error copying timezone (from %s): %s"
+#~ msgstr "複製(%s)時區資料時發生錯誤: %s"
+
+#, python-format
+#~ msgid "Changing permission of timezone: %s"
+#~ msgstr "改變時區資料權限: %s"
+
+#~ msgid "About this XO"
+#~ msgstr "關於XO"
+
+#
+#~ msgid "Add to journal"
+#~ msgstr "增加到日誌"
+
+#
+#~ msgid "Reboot"
+#~ msgstr "重新啟動"
+
+#
+#~ msgid "My Battery life"
+#~ msgstr "我的電池狀態"
+
+#
+#~ msgid "Battery charging"
+#~ msgstr "電池充電中"
+
+#
+#~ msgid "Battery discharging"
+#~ msgstr "電池放電中"
+
+#
+#~ msgid "Battery fully charged"
+#~ msgstr "電池已充電完成"
+
+#
+#~ msgid "Share with:"
+#~ msgstr "分享給:"
+
+#
+#~ msgid "Private"
+#~ msgstr "私人"
+
+#
+#~ msgid "My Neighborhood"
+#~ msgstr "我的鄰居"
+
+#
+#~ msgid "Undo"
+#~ msgstr "復原"
+
+#
+#~ msgid "Redo"
+#~ msgstr "取消復原"
+
+#
+#~ msgid "Paste"
+#~ msgstr "貼上"
+
+#, python-format
+#~ msgid "%s Activity"
+#~ msgstr "%s活動"
+
+#~ msgid "Keep error"
+#~ msgstr "保存時發生錯誤"
+
+#~ msgid "Keep error: all changes will be lost"
+#~ msgstr "保存時發生錯誤: 所有的改變將被取消"
+
+#~ msgid "Don't stop"
+#~ msgstr "取消關閉"
+
+#~ msgid "Stop anyway"
+#~ msgstr "直接關閉"
+
+#~ msgid "Continue"
+#~ msgstr "繼續活動"
+
+#
+#~ msgid "OK"
+#~ msgstr "確定"
+
+#, python-format
+#~ msgid "%d year"
+#~ msgstr "%d年"
+
+#, python-format
+#~ msgid "%d years"
+#~ msgstr "%d年"
+
+#, python-format
+#~ msgid "%d month"
+#~ msgstr "%d月"
+
+#, python-format
+#~ msgid "%d months"
+#~ msgstr "%d月"
+
+#, python-format
+#~ msgid "%d week"
+#~ msgstr "%d週"
+
+#, python-format
+#~ msgid "%d weeks"
+#~ msgstr "%d週"
+
+#, python-format
+#~ msgid "%d day"
+#~ msgstr "%d日"
+
+#, python-format
+#~ msgid "%d days"
+#~ msgstr "%d日"
+
+#, python-format
+#~ msgid "%d hour"
+#~ msgstr "%d時"
+
+#, python-format
+#~ msgid "%d hours"
+#~ msgstr "%d時"
+
+#, python-format
+#~ msgid "%d minute"
+#~ msgstr "%d分"
+
+#, python-format
+#~ msgid "%d minutes"
+#~ msgstr "%d分"
+
+#, python-format
+#~ msgid "%d second"
+#~ msgstr "%d秒"
+
+#
+#~ msgid " and "
+#~ msgstr "又"
+
+#
+# Only show disconnect when there's a mesh device, because mesh takes
+# priority over the normal wireless device. NM doesn't have a "disconnect"
+# method for a device either (for various reasons) so this doesn't
+# have a good mapping
+#, python-format
+#~ msgid ", "
+#~ msgstr ","
diff --git a/shell/src/Makefile.am b/shell/src/Makefile.am
new file mode 100644
index 0000000..83571a4
--- /dev/null
+++ b/shell/src/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = jarabe
diff --git a/shell/src/jarabe/.gitignore b/shell/src/jarabe/.gitignore
new file mode 100644
index 0000000..4acd06b
--- /dev/null
+++ b/shell/src/jarabe/.gitignore
@@ -0,0 +1 @@
+config.py
diff --git a/shell/src/jarabe/Makefile.am b/shell/src/jarabe/Makefile.am
new file mode 100644
index 0000000..84bb213
--- /dev/null
+++ b/shell/src/jarabe/Makefile.am
@@ -0,0 +1,16 @@
+SUBDIRS = \
+ controlpanel \
+ desktop \
+ frame \
+ journal \
+ model \
+ view \
+ intro \
+ util
+
+sugardir = $(pythondir)/jarabe
+sugar_PYTHON = \
+ __init__.py
+
+nodist_sugar_PYTHON = config.py
+
diff --git a/shell/src/jarabe/__init__.py b/shell/src/jarabe/__init__.py
new file mode 100644
index 0000000..41b4b1c
--- /dev/null
+++ b/shell/src/jarabe/__init__.py
@@ -0,0 +1,26 @@
+"""OLPC Sugar Graphical "Shell" Interface
+
+Provides the shell-level operations for managing
+the OLPC laptop computers. It interacts heavily
+with (and depends upon) the Sugar UI libraries.
+
+This is a "graphical" shell, the name does not
+refer to a command-line "shell" interface.
+"""
+
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
diff --git a/shell/src/jarabe/config.py.in b/shell/src/jarabe/config.py.in
new file mode 100644
index 0000000..6c418e9
--- /dev/null
+++ b/shell/src/jarabe/config.py.in
@@ -0,0 +1,26 @@
+# Copyright (C) 2008 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+# pylint: disable-msg=C0301
+
+prefix = '@prefix@'
+data_path = '@prefix@/share/sugar/data'
+shell_path = '@prefix@/share/sugar/shell'
+locale_path = '@prefix@/share/locale'
+ext_path = '@prefix@/share/sugar/extensions'
+activities_path = "@prefix@/share/sugar/activities"
+version = '@SUCROSE_VERSION@'
+
diff --git a/shell/src/jarabe/controlpanel/Makefile.am b/shell/src/jarabe/controlpanel/Makefile.am
new file mode 100644
index 0000000..1de2961
--- /dev/null
+++ b/shell/src/jarabe/controlpanel/Makefile.am
@@ -0,0 +1,10 @@
+sugardir = $(pythondir)/jarabe/controlpanel
+sugar_PYTHON = \
+ __init__.py \
+ cmd.py \
+ gui.py \
+ inlinealert.py \
+ sectionview.py \
+ toolbar.py
+
+
diff --git a/shell/src/jarabe/controlpanel/__init__.py b/shell/src/jarabe/controlpanel/__init__.py
new file mode 100644
index 0000000..a9dd95a
--- /dev/null
+++ b/shell/src/jarabe/controlpanel/__init__.py
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
diff --git a/shell/src/jarabe/controlpanel/cmd.py b/shell/src/jarabe/controlpanel/cmd.py
new file mode 100644
index 0000000..7144b33
--- /dev/null
+++ b/shell/src/jarabe/controlpanel/cmd.py
@@ -0,0 +1,158 @@
+# Copyright (C) 2007, 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import getopt
+import os
+from gettext import gettext as _
+import traceback
+import logging
+
+from jarabe import config
+
+_RESTART = 1
+
+_same_option_warning = _("sugar-control-panel: WARNING, found more than"
+ " one option with the same name: %s module: %r")
+_no_option_error = _("sugar-control-panel: key=%s not an available option")
+_general_error = _("sugar-control-panel: %s")
+
+def cmd_help():
+ '''Print the help to the screen'''
+ # TRANS: Translators, there's a empty line at the end of this string,
+ # which must appear in the translated string (msgstr) as well.
+ print _('Usage: sugar-control-panel [ option ] key [ args ... ] \n\
+ Control for the sugar environment. \n\
+ Options: \n\
+ -h show this help message and exit \n\
+ -l list all the available options \n\
+ -h key show information about this key \n\
+ -g key get the current value of the key \n\
+ -s key set the current value for the key \n\
+ -c key clear the current value for the key \n\
+ ')
+
+def note_restart():
+ '''Instructions how to restart sugar'''
+ print _('To apply your changes you have to restart sugar.\n' +
+ 'Hit ctrl+alt+erase on the keyboard to trigger a restart.')
+
+def load_modules():
+ '''Build a list of pointers to available modules and import them.
+ '''
+ modules = []
+
+ path = os.path.join(config.ext_path, 'cpsection')
+ folder = os.listdir(path)
+
+ for item in folder:
+ if os.path.isdir(os.path.join(path, item)) and \
+ os.path.exists(os.path.join(path, item, 'model.py')):
+ try:
+ module = __import__('.'.join(('cpsection', item, 'model')),
+ globals(), locals(), ['model'])
+ except Exception:
+ logging.error('Exception while loading extension:\n' + \
+ ''.join(traceback.format_exception(*sys.exc_info())))
+ else:
+ modules.append(module)
+
+ return modules
+
+def main():
+ try:
+ options, args = getopt.getopt(sys.argv[1:], "h:s:g:c:l", [])
+ except getopt.GetoptError:
+ cmd_help()
+ sys.exit(2)
+
+ if not options:
+ cmd_help()
+ sys.exit(2)
+
+ modules = load_modules()
+
+ for option, key in options:
+ found = 0
+ if option in ("-h"):
+ for module in modules:
+ method = getattr(module, 'set_' + key, None)
+ if method:
+ found += 1
+ if found == 1:
+ print method.__doc__
+ else:
+ print _(_same_option_warning % (key, module))
+ if found == 0:
+ print _(_no_option_error % key)
+ if option in ("-l"):
+ for module in modules:
+ methods = dir(module)
+ print '%s:' % module.__name__.split('.')[1]
+ for method in methods:
+ if method.startswith('get_'):
+ print ' %s' % method[4:]
+ elif method.startswith('clear_'):
+ print " %s (use the -c argument with this option)" \
+ % method[6:]
+ if option in ("-g"):
+ for module in modules:
+ method = getattr(module, 'print_' + key, None)
+ if method:
+ found += 1
+ if found == 1:
+ try:
+ method()
+ except Exception, detail:
+ print _(_general_error % detail)
+ else:
+ print _(_same_option_warning % (key, module))
+ if found == 0:
+ print _(_no_option_error % key)
+ if option in ("-s"):
+ for module in modules:
+ method = getattr(module, 'set_' + key, None)
+ if method:
+ note = 0
+ found += 1
+ if found == 1:
+ try:
+ note = method(*args)
+ except Exception, detail:
+ print _(_general_error % detail)
+ if note == _RESTART:
+ note_restart()
+ else:
+ print _(_same_option_warning % (key, module))
+ if found == 0:
+ print _(_no_option_error % key)
+ if option in ("-c"):
+ for module in modules:
+ method = getattr(module, 'clear_' + key, None)
+ if method:
+ note = 0
+ found += 1
+ if found == 1:
+ try:
+ note = method(*args)
+ except Exception, detail:
+ print _(_general_error % detail)
+ if note == _RESTART:
+ note_restart()
+ else:
+ print _(_same_option_warning % (key, module))
+ if found == 0:
+ print _(_no_option_error % key)
diff --git a/shell/src/jarabe/controlpanel/gui.py b/shell/src/jarabe/controlpanel/gui.py
new file mode 100644
index 0000000..51d9820
--- /dev/null
+++ b/shell/src/jarabe/controlpanel/gui.py
@@ -0,0 +1,431 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+from gettext import gettext as _
+import sys
+import traceback
+
+import gobject
+import gtk
+
+from sugar.graphics.icon import Icon
+from sugar.graphics import style
+from sugar.graphics.alert import Alert
+
+from jarabe.model.session import get_session_manager
+from jarabe.controlpanel.toolbar import MainToolbar
+from jarabe.controlpanel.toolbar import SectionToolbar
+from jarabe import config
+
+_logger = logging.getLogger('ControlPanel')
+_MAX_COLUMNS = 5
+
+class ControlPanel(gtk.Window):
+ __gtype_name__ = 'SugarControlPanel'
+
+ def __init__(self):
+ gtk.Window.__init__(self)
+
+ self.set_border_width(style.LINE_WIDTH)
+ offset = style.GRID_CELL_SIZE
+ width = gtk.gdk.screen_width() - offset * 2
+ height = gtk.gdk.screen_height() - offset * 2
+ self.set_size_request(width, height)
+ self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.set_decorated(False)
+ self.set_resizable(False)
+ self.set_modal(True)
+
+ self._toolbar = None
+ self._canvas = None
+ self._table = None
+ self._scrolledwindow = None
+ self._separator = None
+ self._section_view = None
+ self._section_toolbar = None
+ self._main_toolbar = None
+
+ self._vbox = gtk.VBox()
+ self._hbox = gtk.HBox()
+ self._vbox.pack_start(self._hbox)
+ self._hbox.show()
+
+ self._main_view = gtk.EventBox()
+ self._hbox.pack_start(self._main_view)
+ self._main_view.modify_bg(gtk.STATE_NORMAL,
+ style.COLOR_BLACK.get_gdk_color())
+ self._main_view.show()
+
+ self.add(self._vbox)
+ self._vbox.show()
+
+ self.connect("realize", self.__realize_cb)
+
+ self._options = self._get_options()
+ self._current_option = None
+ self._setup_main()
+ self._setup_section()
+ self._show_main_view()
+
+ def __realize_cb(self, widget):
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.window.set_accept_focus(True)
+
+ def _set_canvas(self, canvas):
+ if self._canvas:
+ self._main_view.remove(self._canvas)
+ if canvas:
+ self._main_view.add(canvas)
+ self._canvas = canvas
+
+ def _set_toolbar(self, toolbar):
+ if self._toolbar:
+ self._vbox.remove(self._toolbar)
+ self._vbox.pack_start(toolbar, False)
+ self._vbox.reorder_child(toolbar, 0)
+ self._toolbar = toolbar
+ if not self._separator:
+ self._separator = gtk.HSeparator()
+ self._vbox.pack_start(self._separator, False)
+ self._vbox.reorder_child(self._separator, 1)
+ self._separator.show()
+
+ def _setup_main(self):
+ self._main_toolbar = MainToolbar()
+
+ self._table = gtk.Table()
+ self._table.set_col_spacings(style.GRID_CELL_SIZE)
+ self._table.set_border_width(style.GRID_CELL_SIZE)
+
+ self._scrolledwindow = gtk.ScrolledWindow()
+ self._scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC,
+ gtk.POLICY_AUTOMATIC)
+ self._scrolledwindow.add_with_viewport(self._table)
+ child = self._scrolledwindow.get_child()
+ child.modify_bg(gtk.STATE_NORMAL, style.COLOR_BLACK.get_gdk_color())
+
+ self._setup_options()
+ self._main_toolbar.connect('stop-clicked',
+ self.__stop_clicked_cb)
+ self._main_toolbar.connect('search-changed',
+ self.__search_changed_cb)
+
+ def _setup_options(self):
+ if not os.path.exists('/ofw'):
+ del self._options['power']
+
+ try:
+ import xklavier
+ except ImportError:
+ del self._options['keyboard']
+
+ row = 0
+ column = 2
+ options = self._options.keys()
+ options.sort()
+
+ for option in options:
+ sectionicon = _SectionIcon(icon_name=self._options[option]['icon'],
+ title=self._options[option]['title'],
+ xo_color=self._options[option]['color'],
+ pixel_size=style.GRID_CELL_SIZE)
+ sectionicon.connect('button_press_event',
+ self.__select_option_cb, option)
+ sectionicon.show()
+
+ if option == 'aboutme':
+ self._table.attach(sectionicon, 0, 1, 0, 1)
+ elif option == 'aboutcomputer':
+ self._table.attach(sectionicon, 1, 2, 0, 1)
+ else:
+ self._table.attach(sectionicon,
+ column, column + 1,
+ row, row + 1)
+ column += 1
+ if column == _MAX_COLUMNS:
+ column = 0
+ row += 1
+
+ self._options[option]['button'] = sectionicon
+
+ def _show_main_view(self):
+ self._set_toolbar(self._main_toolbar)
+ self._main_toolbar.show()
+ self._set_canvas(self._scrolledwindow)
+ self._main_view.modify_bg(gtk.STATE_NORMAL,
+ style.COLOR_BLACK.get_gdk_color())
+ self._table.show()
+ self._scrolledwindow.show()
+ entry = self._main_toolbar.get_entry()
+ entry.grab_focus()
+ entry.set_text('')
+
+ def _update(self, query):
+ for option in self._options:
+ found = False
+ for key in self._options[option]['keywords']:
+ if query.lower() in key.lower():
+ self._options[option]['button'].set_sensitive(True)
+ found = True
+ break
+ if not found:
+ self._options[option]['button'].set_sensitive(False)
+
+ def _setup_section(self):
+ self._section_toolbar = SectionToolbar()
+ self._section_toolbar.connect('cancel-clicked',
+ self.__cancel_clicked_cb)
+ self._section_toolbar.connect('accept-clicked',
+ self.__accept_clicked_cb)
+
+ def show_section_view(self, option):
+ self._set_toolbar(self._section_toolbar)
+
+ icon = self._section_toolbar.get_icon()
+ icon.set_from_icon_name(self._options[option]['icon'],
+ gtk.ICON_SIZE_LARGE_TOOLBAR)
+ icon.props.xo_color = self._options[option]['color']
+ title = self._section_toolbar.get_title()
+ title.set_text(self._options[option]['title'])
+ self._section_toolbar.show()
+
+ self._current_option = option
+
+ mod = __import__('.'.join(('cpsection', option, 'view')),
+ globals(), locals(), ['view'])
+ view_class = getattr(mod, self._options[option]['view'], None)
+
+ mod = __import__('.'.join(('cpsection', option, 'model')),
+ globals(), locals(), ['model'])
+ model = ModelWrapper(mod)
+
+ self._section_view = view_class(model,
+ self._options[option]['alerts'])
+
+ self._set_canvas(self._section_view)
+ self._section_view.show()
+ self._section_view.connect('notify::is-valid',
+ self.__valid_section_cb)
+ self._section_view.connect('request-close',
+ self.__close_request_cb)
+ self._main_view.modify_bg(gtk.STATE_NORMAL,
+ style.COLOR_WHITE.get_gdk_color())
+
+ def set_section_view_auto_close(self):
+ '''Automatically close the control panel if there is "nothing to do"
+ '''
+ self._section_view.auto_close = True
+
+ def _get_options(self):
+ '''Get the available option information from the extensions
+ '''
+ options = {}
+
+ path = os.path.join(config.ext_path, 'cpsection')
+ folder = os.listdir(path)
+
+ for item in folder:
+ if os.path.isdir(os.path.join(path, item)) and \
+ os.path.exists(os.path.join(path, item, '__init__.py')):
+ try:
+ mod = __import__('.'.join(('cpsection', item)),
+ globals(), locals(), [item])
+ view_class = getattr(mod, 'CLASS', None)
+ if view_class is not None:
+ options[item] = {}
+ options[item]['alerts'] = []
+ options[item]['view'] = view_class
+ options[item]['icon'] = getattr(mod, 'ICON', item)
+ options[item]['title'] = getattr(mod, 'TITLE', item)
+ options[item]['color'] = getattr(mod, 'COLOR', None)
+ keywords = getattr(mod, 'KEYWORDS', [])
+ keywords.append(options[item]['title'].lower())
+ if item not in keywords:
+ keywords.append(item)
+ options[item]['keywords'] = keywords
+ else:
+ _logger.error('There is no CLASS constant specifieds ' \
+ 'in the view file \'%s\'.' % item)
+ except Exception:
+ logging.error('Exception while loading extension:\n' + \
+ ''.join(traceback.format_exception(*sys.exc_info())))
+
+ return options
+
+ def __cancel_clicked_cb(self, widget):
+ self._section_view.undo()
+ self._options[self._current_option]['alerts'] = []
+ self._section_toolbar.accept_button.set_sensitive(True)
+ self._show_main_view()
+
+ def __accept_clicked_cb(self, widget):
+ if self._section_view.needs_restart:
+ self._section_toolbar.accept_button.set_sensitive(False)
+ self._section_toolbar.cancel_button.set_sensitive(False)
+ alert = Alert()
+ alert.props.title = _('Warning')
+ alert.props.msg = _('Changes require restart')
+
+ icon = Icon(icon_name='dialog-cancel')
+ alert.add_button(gtk.RESPONSE_CANCEL, _('Cancel changes'), icon)
+ icon.show()
+
+ if self._current_option != 'aboutme':
+ icon = Icon(icon_name='dialog-ok')
+ alert.add_button(gtk.RESPONSE_ACCEPT, _('Later'), icon)
+ icon.show()
+
+ icon = Icon(icon_name='system-restart')
+ alert.add_button(gtk.RESPONSE_APPLY, _('Restart now'), icon)
+ icon.show()
+
+ self._vbox.pack_start(alert, False)
+ self._vbox.reorder_child(alert, 2)
+ alert.connect('response', self.__response_cb)
+ alert.show()
+ else:
+ self._show_main_view()
+
+ def __response_cb(self, alert, response_id):
+ self._vbox.remove(alert)
+ self._section_toolbar.accept_button.set_sensitive(True)
+ self._section_toolbar.cancel_button.set_sensitive(True)
+ if response_id is gtk.RESPONSE_CANCEL:
+ self._section_view.undo()
+ self._section_view.setup()
+ self._options[self._current_option]['alerts'] = []
+ elif response_id is gtk.RESPONSE_ACCEPT:
+ self._options[self._current_option]['alerts'] = \
+ self._section_view.restart_alerts
+ self._show_main_view()
+ elif response_id is gtk.RESPONSE_APPLY:
+ session_manager = get_session_manager()
+ session_manager.logout()
+
+ def __select_option_cb(self, button, event, option):
+ self.show_section_view(option)
+
+ def __search_changed_cb(self, maintoolbar, query):
+ self._update(query)
+
+ def __stop_clicked_cb(self, widget):
+ self.destroy()
+
+ def __close_request_cb(self, widget, event=None):
+ self.destroy()
+
+ def __valid_section_cb(self, section_view, pspec):
+ section_is_valid = section_view.props.is_valid
+ self._section_toolbar.accept_button.set_sensitive(section_is_valid)
+
+class ModelWrapper(object):
+ def __init__(self, module):
+ self._module = module
+ self._options = {}
+ self._setup()
+
+ def _setup(self):
+ methods = dir(self._module)
+ for method in methods:
+ if method.startswith('get_') and method[4:] != 'color':
+ try:
+ self._options[method[4:]] = getattr(self._module, method)()
+ except Exception:
+ self._options[method[4:]] = None
+
+ def __getattr__(self, name):
+ return getattr(self._module, name)
+
+ def undo(self):
+ for key in self._options.keys():
+ method = getattr(self._module, 'set_' + key, None)
+ if method and self._options[key] is not None:
+ try:
+ method(self._options[key])
+ except Exception, detail:
+ _logger.debug('Error undo option: %s', detail)
+
+class _SectionIcon(gtk.EventBox):
+ __gtype_name__ = "SugarSectionIcon"
+
+ __gproperties__ = {
+ 'icon-name' : (str, None, None, None,
+ gobject.PARAM_READWRITE),
+ 'pixel-size' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'xo-color' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'title' : (str, None, None, None,
+ gobject.PARAM_READWRITE)
+ }
+
+ def __init__(self, **kwargs):
+ self._icon_name = None
+ self._pixel_size = style.GRID_CELL_SIZE
+ self._xo_color = None
+ self._title = 'No Title'
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ self._vbox = gtk.VBox()
+ self._icon = Icon(icon_name=self._icon_name,
+ pixel_size=self._pixel_size,
+ xo_color=self._xo_color)
+ self._vbox.pack_start(self._icon, expand=False, fill=False)
+
+ self._label = gtk.Label(self._title)
+ self._label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_WHITE.get_gdk_color())
+ self._vbox.pack_start(self._label, expand=False, fill=False)
+
+ self._vbox.set_spacing(style.DEFAULT_SPACING)
+ self.set_visible_window(False)
+ self.set_app_paintable(True)
+ self.set_events(gtk.gdk.BUTTON_PRESS_MASK)
+
+ self.add(self._vbox)
+ self._vbox.show()
+ self._label.show()
+ self._icon.show()
+
+ def get_icon(self):
+ return self._icon
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'icon-name':
+ if self._icon_name != value:
+ self._icon_name = value
+ elif pspec.name == 'pixel-size':
+ if self._pixel_size != value:
+ self._pixel_size = value
+ elif pspec.name == 'xo-color':
+ if self._xo_color != value:
+ self._xo_color = value
+ elif pspec.name == 'title':
+ if self._title != value:
+ self._title = value
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'icon-name':
+ return self._icon_name
+ elif pspec.name == 'pixel-size':
+ return self._pixel_size
+ elif pspec.name == 'xo-color':
+ return self._xo_color
+ elif pspec.name == 'title':
+ return self._title
diff --git a/shell/src/jarabe/controlpanel/inlinealert.py b/shell/src/jarabe/controlpanel/inlinealert.py
new file mode 100644
index 0000000..b1880da
--- /dev/null
+++ b/shell/src/jarabe/controlpanel/inlinealert.py
@@ -0,0 +1,83 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gobject
+import pango
+
+from sugar.graphics import style
+from sugar.graphics.icon import Icon
+
+class InlineAlert(gtk.HBox):
+ """UI interface for Inline alerts
+
+ Inline alerts are different from the other alerts beause they are
+ no dialogs, they only inform about a current event.
+
+ Properties:
+ 'msg': the message of the alert,
+ 'icon': the icon that appears at the far left
+ See __gproperties__
+ """
+
+ __gtype_name__ = 'SugarInlineAlert'
+
+ __gproperties__ = {
+ 'msg' : (str, None, None, None,
+ gobject.PARAM_READWRITE),
+ 'icon' : (object, None, None,
+ gobject.PARAM_WRITABLE)
+ }
+
+ def __init__(self, **kwargs):
+
+ self._msg = None
+ self._msg_color = None
+ self._icon = Icon(icon_name='emblem-warning',
+ fill_color=style.COLOR_SELECTION_GREY.get_svg(),
+ stroke_color=style.COLOR_WHITE.get_svg())
+
+ self._msg_label = gtk.Label()
+ self._msg_label.set_max_width_chars(50)
+ self._msg_label.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
+ self._msg_label.set_alignment(0, 0.5)
+ self._msg_label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ self.set_spacing(style.DEFAULT_SPACING)
+ self.modify_bg(gtk.STATE_NORMAL,
+ style.COLOR_WHITE.get_gdk_color())
+
+ self.pack_start(self._icon, False)
+ self.pack_start(self._msg_label, False)
+ self._msg_label.show()
+ self._icon.show()
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'msg':
+ if self._msg != value:
+ self._msg = value
+ self._msg_label.set_markup(self._msg)
+ elif pspec.name == 'icon':
+ if self._icon != value:
+ self._icon = value
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'msg':
+ return self._msg
+
diff --git a/shell/src/jarabe/controlpanel/sectionview.py b/shell/src/jarabe/controlpanel/sectionview.py
new file mode 100644
index 0000000..4de27a2
--- /dev/null
+++ b/shell/src/jarabe/controlpanel/sectionview.py
@@ -0,0 +1,55 @@
+# Copyright (C) 2008, OLPC
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gobject
+import gtk
+from gettext import gettext as _
+
+class SectionView(gtk.VBox):
+ __gtype_name__ = 'SugarSectionView'
+
+ __gsignals__ = {
+ 'request-close': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([]))
+ }
+
+ __gproperties__ = {
+ 'is_valid' : (bool, None, None, True,
+ gobject.PARAM_READWRITE)
+ }
+
+ _APPLY_TIMEOUT = 1000
+
+ def __init__(self):
+ gtk.VBox.__init__(self)
+ self._is_valid = True
+ self.auto_close = False
+ self.needs_restart = False
+ self.restart_alerts = []
+ self.restart_msg = _('Changes require restart')
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'is-valid':
+ if self._is_valid != value:
+ self._is_valid = value
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'is-valid':
+ return self._is_valid
+
+ def undo(self):
+ '''Undo here the changes that have been made in this section.'''
+ pass
diff --git a/shell/src/jarabe/controlpanel/toolbar.py b/shell/src/jarabe/controlpanel/toolbar.py
new file mode 100644
index 0000000..320a8eb
--- /dev/null
+++ b/shell/src/jarabe/controlpanel/toolbar.py
@@ -0,0 +1,157 @@
+# Copyright (C) 2007, 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gettext
+import gobject
+
+_ = lambda msg: gettext.dgettext('sugar', msg)
+
+from sugar.graphics.icon import Icon
+from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics import iconentry
+from sugar.graphics import style
+
+class MainToolbar(gtk.Toolbar):
+ """ Main toolbar of the control panel
+ """
+ __gtype_name__ = 'MainToolbar'
+
+ __gsignals__ = {
+ 'stop-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ 'search-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str]))
+ }
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self._add_separator()
+
+ tool_item = gtk.ToolItem()
+ self.insert(tool_item, -1)
+ tool_item.show()
+ self._search_entry = iconentry.IconEntry()
+ self._search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY,
+ 'system-search')
+ self._search_entry.add_clear_button()
+ self._search_entry.set_width_chars(25)
+ self._search_entry.connect('changed', self.__search_entry_changed_cb)
+ tool_item.add(self._search_entry)
+ self._search_entry.show()
+
+ self._add_separator(True)
+
+ self.stop = ToolButton(icon_name='dialog-cancel')
+ self.stop.set_tooltip(_('Done'))
+ self.stop.connect('clicked', self.__stop_clicked_cb)
+ self.stop.show()
+ self.insert(self.stop, -1)
+ self.stop.show()
+
+ def get_entry(self):
+ return self._search_entry
+
+ def _add_separator(self, expand=False):
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ if expand:
+ separator.set_expand(True)
+ else:
+ separator.set_size_request(style.DEFAULT_SPACING, -1)
+ self.insert(separator, -1)
+ separator.show()
+
+ def __search_entry_changed_cb(self, search_entry):
+ self.emit('search-changed', search_entry.props.text)
+
+ def __stop_clicked_cb(self, button):
+ self.emit('stop-clicked')
+
+class SectionToolbar(gtk.Toolbar):
+ """ Toolbar of the sections of the control panel
+ """
+ __gtype_name__ = 'SectionToolbar'
+
+ __gsignals__ = {
+ 'cancel-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ 'accept-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([]))
+ }
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self._add_separator()
+
+ self._icon = Icon()
+ self._add_widget(self._icon)
+
+ self._add_separator()
+
+ self._title = gtk.Label()
+ self._add_widget(self._title)
+
+ self._add_separator(True)
+
+ self.cancel_button = ToolButton('dialog-cancel')
+ self.cancel_button.set_tooltip(_('Cancel'))
+ self.cancel_button.connect('clicked', self.__cancel_button_clicked_cb)
+ self.insert(self.cancel_button, -1)
+ self.cancel_button.show()
+
+ self.accept_button = ToolButton('dialog-ok')
+ self.accept_button.set_tooltip(_('Ok'))
+ self.accept_button.connect('clicked', self.__accept_button_clicked_cb)
+ self.insert(self.accept_button, -1)
+ self.accept_button.show()
+
+ def get_icon(self):
+ return self._icon
+
+ def get_title(self):
+ return self._title
+
+ def _add_separator(self, expand=False):
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ if expand:
+ separator.set_expand(True)
+ else:
+ separator.set_size_request(style.DEFAULT_SPACING, -1)
+ self.insert(separator, -1)
+ separator.show()
+
+ def _add_widget(self, widget, expand=False):
+ tool_item = gtk.ToolItem()
+ tool_item.set_expand(expand)
+
+ tool_item.add(widget)
+ widget.show()
+
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ def __cancel_button_clicked_cb(self, widget, data=None):
+ self.emit('cancel-clicked')
+
+ def __accept_button_clicked_cb(self, widget, data=None):
+ self.emit('accept-clicked')
+
diff --git a/shell/src/jarabe/desktop/Makefile.am b/shell/src/jarabe/desktop/Makefile.am
new file mode 100644
index 0000000..25fb0b4
--- /dev/null
+++ b/shell/src/jarabe/desktop/Makefile.am
@@ -0,0 +1,18 @@
+sugardir = $(pythondir)/jarabe/desktop
+sugar_PYTHON = \
+ __init__.py \
+ activitieslist.py \
+ favoritesview.py \
+ favoriteslayout.py \
+ friendview.py \
+ grid.py \
+ groupbox.py \
+ homebox.py \
+ homewindow.py \
+ keydialog.py \
+ meshbox.py \
+ networkviews.py \
+ schoolserver.py \
+ snowflakelayout.py \
+ spreadlayout.py \
+ transitionbox.py
diff --git a/shell/src/jarabe/desktop/__init__.py b/shell/src/jarabe/desktop/__init__.py
new file mode 100644
index 0000000..a9dd95a
--- /dev/null
+++ b/shell/src/jarabe/desktop/__init__.py
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
diff --git a/shell/src/jarabe/desktop/activitieslist.py b/shell/src/jarabe/desktop/activitieslist.py
new file mode 100644
index 0000000..e14d0f7
--- /dev/null
+++ b/shell/src/jarabe/desktop/activitieslist.py
@@ -0,0 +1,451 @@
+# Copyright (C) 2008 One Laptop Per Child
+# Copyright (C) 2009 Tomeu Vizoso
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+from gettext import gettext as _
+
+import gobject
+import pango
+import gconf
+import gtk
+
+from sugar import util
+from sugar.graphics import style
+from sugar.graphics.icon import Icon, CellRendererIcon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.alert import Alert
+from sugar.activity import activityfactory
+from sugar.activity.activityhandle import ActivityHandle
+
+from jarabe.model import bundleregistry
+from jarabe.view.palettes import ActivityPalette
+from jarabe.view import launcher
+from jarabe.journal import misc
+
+class ActivitiesTreeView(gtk.TreeView):
+ __gtype_name__ = 'SugarActivitiesTreeView'
+
+ __gsignals__ = {
+ 'erase-activated' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([str]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._query = ''
+
+ self.modify_base(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color())
+ self.set_headers_visible(False)
+ selection = self.get_selection()
+ selection.set_mode(gtk.SELECTION_NONE)
+
+ model = ListModel()
+ model.set_visible_func(self.__model_visible_cb)
+ self.set_model(model)
+
+ cell_favorite = CellRendererFavorite(self)
+ cell_favorite.connect('clicked', self.__favorite_clicked_cb)
+
+ column = gtk.TreeViewColumn()
+ column.pack_start(cell_favorite)
+ column.set_cell_data_func(cell_favorite, self.__favorite_set_data_cb)
+ self.append_column(column)
+
+ cell_icon = CellRendererActivityIcon(self)
+ cell_icon.connect('erase-activated', self.__erase_activated_cb)
+ cell_icon.connect('clicked', self.__icon_clicked_cb)
+
+ column = gtk.TreeViewColumn()
+ column.pack_start(cell_icon)
+ column.add_attribute(cell_icon, 'file-name', ListModel.COLUMN_ICON)
+ self.append_column(column)
+
+ cell_text = gtk.CellRendererText()
+ cell_text.props.ellipsize = pango.ELLIPSIZE_MIDDLE
+ cell_text.props.ellipsize_set = True
+
+ column = gtk.TreeViewColumn()
+ column.props.sizing = gtk.TREE_VIEW_COLUMN_GROW_ONLY
+ column.props.expand = True
+ column.set_sort_column_id(ListModel.COLUMN_TITLE)
+ column.pack_start(cell_text)
+ column.add_attribute(cell_text, 'markup', ListModel.COLUMN_TITLE)
+ self.append_column(column)
+
+ cell_text = gtk.CellRendererText()
+ cell_text.props.xalign = 1
+
+ column = gtk.TreeViewColumn()
+ column.set_alignment(1)
+ column.props.sizing = gtk.TREE_VIEW_COLUMN_GROW_ONLY
+ column.props.resizable = True
+ column.props.reorderable = True
+ column.props.expand = True
+ column.set_sort_column_id(ListModel.COLUMN_VERSION)
+ column.pack_start(cell_text)
+ column.add_attribute(cell_text, 'text', ListModel.COLUMN_VERSION_TEXT)
+ self.append_column(column)
+
+ cell_text = gtk.CellRendererText()
+ cell_text.props.xalign = 1
+
+ column = gtk.TreeViewColumn()
+ column.set_alignment(1)
+ column.props.sizing = gtk.TREE_VIEW_COLUMN_GROW_ONLY
+ column.props.resizable = True
+ column.props.reorderable = True
+ column.props.expand = True
+ column.set_sort_column_id(ListModel.COLUMN_DATE)
+ column.pack_start(cell_text)
+ column.add_attribute(cell_text, 'text', ListModel.COLUMN_DATE_TEXT)
+ self.append_column(column)
+
+ self.set_search_column(ListModel.COLUMN_TITLE)
+
+ def __erase_activated_cb(self, cell_renderer, bundle_id):
+ self.emit('erase-activated', bundle_id)
+
+ def __favorite_set_data_cb(self, column, cell, model, tree_iter):
+ favorite = model[tree_iter][ListModel.COLUMN_FAVORITE]
+ if favorite:
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ cell.props.xo_color = color
+ else:
+ cell.props.xo_color = None
+
+ def __favorite_clicked_cb(self, cell, path):
+ row = self.get_model()[path]
+ registry = bundleregistry.get_registry()
+ registry.set_bundle_favorite(row[ListModel.COLUMN_BUNDLE_ID],
+ row[ListModel.COLUMN_VERSION],
+ not row[ListModel.COLUMN_FAVORITE])
+
+ def __icon_clicked_cb(self, cell, path):
+ row = self.get_model()[path]
+
+ registry = bundleregistry.get_registry()
+ bundle = registry.get_bundle(row[ListModel.COLUMN_BUNDLE_ID])
+
+ misc.launch(bundle)
+
+ def set_filter(self, query):
+ self._query = query.lower()
+ self.get_model().refilter()
+
+ def __model_visible_cb(self, model, tree_iter):
+ title = model[tree_iter][ListModel.COLUMN_TITLE]
+ return title is not None and title.lower().find(self._query) > -1
+
+class ListModel(gtk.TreeModelSort):
+ __gtype_name__ = 'SugarListModel'
+
+ COLUMN_BUNDLE_ID = 0
+ COLUMN_FAVORITE = 1
+ COLUMN_ICON = 2
+ COLUMN_TITLE = 3
+ COLUMN_VERSION = 4
+ COLUMN_VERSION_TEXT = 5
+ COLUMN_DATE = 6
+ COLUMN_DATE_TEXT = 7
+
+ def __init__(self):
+ self._model = gtk.ListStore(str, bool, str, str, int, str, int, str)
+ self._model_filter = self._model.filter_new()
+ gtk.TreeModelSort.__init__(self, self._model_filter)
+
+ gobject.idle_add(self.__connect_to_bundle_registry_cb)
+
+ def __connect_to_bundle_registry_cb(self):
+ registry = bundleregistry.get_registry()
+ for info in registry:
+ self._add_activity(info)
+ registry.connect('bundle-added', self.__activity_added_cb)
+ registry.connect('bundle-changed', self.__activity_changed_cb)
+ registry.connect('bundle-removed', self.__activity_removed_cb)
+
+ def __activity_added_cb(self, activity_registry, activity_info):
+ self._add_activity(activity_info)
+
+ def __activity_changed_cb(self, activity_registry, activity_info):
+ bundle_id = activity_info.get_bundle_id()
+ version = activity_info.get_activity_version()
+ favorite = activity_registry.is_bundle_favorite(bundle_id, version)
+ for row in self._model:
+ if row[ListModel.COLUMN_BUNDLE_ID] == bundle_id and \
+ row[ListModel.COLUMN_VERSION] == version:
+ row[ListModel.COLUMN_FAVORITE] = favorite
+ return
+
+ def __activity_removed_cb(self, activity_registry, activity_info):
+ bundle_id = activity_info.get_bundle_id()
+ version = activity_info.get_activity_version()
+ for row in self._model:
+ if row[ListModel.COLUMN_BUNDLE_ID] == bundle_id and \
+ row[ListModel.COLUMN_VERSION] == version:
+ self._model.remove(row.iter)
+ return
+
+ def _add_activity(self, activity_info):
+ if activity_info.get_bundle_id() == 'org.laptop.JournalActivity':
+ return
+
+ timestamp = activity_info.get_installation_time()
+ version = activity_info.get_activity_version()
+
+ registry = bundleregistry.get_registry()
+ favorite = registry.is_bundle_favorite(activity_info.get_bundle_id(),
+ version)
+
+ tag_list = activity_info.get_tags()
+ if tag_list is None or not tag_list:
+ title = '<b>%s</b>' % activity_info.get_name()
+ else:
+ tags = ', '.join(tag_list)
+ title = '<b>%s</b>\n' \
+ '<span style="italic" weight="light">%s</span>' % \
+ (activity_info.get_name(), tags)
+
+ self._model.append([activity_info.get_bundle_id(),
+ favorite,
+ activity_info.get_icon(),
+ title,
+ version,
+ _('Version %s') % version,
+ timestamp,
+ util.timestamp_to_elapsed_string(timestamp)])
+
+ def set_visible_func(self, func):
+ self._model_filter.set_visible_func(func)
+
+ def refilter(self):
+ self._model_filter.refilter()
+
+class CellRendererFavorite(CellRendererIcon):
+ __gtype_name__ = 'SugarCellRendererFavorite'
+
+ def __init__(self, tree_view):
+ CellRendererIcon.__init__(self, tree_view)
+
+ self.props.width = style.GRID_CELL_SIZE
+ self.props.height = style.GRID_CELL_SIZE
+ self.props.size = style.SMALL_ICON_SIZE
+ self.props.icon_name = 'emblem-favorite'
+ self.props.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
+ self.props.prelit_stroke_color = style.COLOR_BUTTON_GREY.get_svg()
+ self.props.prelit_fill_color = style.COLOR_BUTTON_GREY.get_svg()
+
+class CellRendererActivityIcon(CellRendererIcon):
+ __gtype_name__ = 'SugarCellRendererActivityIcon'
+
+ __gsignals__ = {
+ 'erase-activated' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([str]))
+ }
+
+ def __init__(self, tree_view):
+ CellRendererIcon.__init__(self, tree_view)
+
+ self.props.width = style.GRID_CELL_SIZE
+ self.props.height = style.GRID_CELL_SIZE
+ self.props.size = style.STANDARD_ICON_SIZE
+ self.props.stroke_color = style.COLOR_BUTTON_GREY.get_svg()
+ self.props.fill_color = style.COLOR_TRANSPARENT.get_svg()
+ self.props.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
+
+ client = gconf.client_get_default()
+ prelit_color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ self.props.prelit_stroke_color = prelit_color.get_stroke_color()
+ self.props.prelit_fill_color = prelit_color.get_fill_color()
+
+ self._tree_view = tree_view
+
+ def create_palette(self):
+ model = self._tree_view.get_model()
+ row = model[self.props.palette_invoker.path]
+ bundle_id = row[ListModel.COLUMN_BUNDLE_ID]
+
+ registry = bundleregistry.get_registry()
+ palette = ActivityListPalette(registry.get_bundle(bundle_id))
+ palette.connect('erase-activated', self.__erase_activated_cb)
+ return palette
+
+ def __erase_activated_cb(self, palette, bundle_id):
+ self.emit('erase-activated', bundle_id)
+
+class ActivitiesList(gtk.VBox):
+ __gtype_name__ = 'SugarActivitiesList'
+
+ def __init__(self):
+ logging.debug('STARTUP: Loading the activities list')
+
+ gobject.GObject.__init__(self)
+
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ scrolled_window.set_shadow_type(gtk.SHADOW_NONE)
+ scrolled_window.connect('key-press-event', self.__key_press_event_cb)
+ self.pack_start(scrolled_window)
+ scrolled_window.show()
+
+ self._tree_view = ActivitiesTreeView()
+ self._tree_view.connect('erase-activated', self.__erase_activated_cb)
+ scrolled_window.add(self._tree_view)
+ self._tree_view.show()
+
+ self._alert = None
+
+ def set_filter(self, query):
+ self._tree_view.set_filter(query)
+
+ def __key_press_event_cb(self, scrolled_window, event):
+ keyname = gtk.gdk.keyval_name(event.keyval)
+
+ vadjustment = scrolled_window.props.vadjustment
+ if keyname == 'Up':
+ if vadjustment.props.value > vadjustment.props.lower:
+ vadjustment.props.value -= vadjustment.props.step_increment
+ elif keyname == 'Down':
+ max_value = vadjustment.props.upper - vadjustment.props.page_size
+ if vadjustment.props.value < max_value:
+ vadjustment.props.value = min(
+ vadjustment.props.value + vadjustment.props.step_increment,
+ max_value)
+ else:
+ return False
+
+ return True
+
+ def add_alert(self, alert):
+ if self._alert is not None:
+ self.remove_alert()
+ self._alert = alert
+ self.pack_start(alert, False)
+ self.reorder_child(alert, 0)
+
+ def remove_alert(self):
+ self.remove(self._alert)
+ self._alert = None
+
+ def __erase_activated_cb(self, tree_view, bundle_id):
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(bundle_id)
+
+ alert = Alert()
+ alert.props.title = _('Confirm erase')
+ alert.props.msg = \
+ _('Confirm erase: Do you want to permanently erase %s?') \
+ % activity_info.get_name()
+
+ cancel_icon = Icon(icon_name='dialog-cancel')
+ alert.add_button(gtk.RESPONSE_CANCEL, _('Keep'), cancel_icon)
+
+ erase_icon = Icon(icon_name='dialog-ok')
+ alert.add_button(gtk.RESPONSE_OK, _('Erase'), erase_icon)
+
+ alert.connect('response', self.__erase_confirmation_dialog_response_cb,
+ bundle_id)
+
+ self.add_alert(alert)
+
+ def __erase_confirmation_dialog_response_cb(self, alert, response_id,
+ bundle_id):
+ self.remove_alert()
+ if response_id == gtk.RESPONSE_OK:
+ registry = bundleregistry.get_registry()
+ bundle = registry.get_bundle(bundle_id)
+ registry.uninstall(bundle)
+
+class ActivityListPalette(ActivityPalette):
+ __gtype_name__ = 'SugarActivityListPalette'
+
+ __gsignals__ = {
+ 'erase-activated' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([str]))
+ }
+
+ def __init__(self, activity_info):
+ ActivityPalette.__init__(self, activity_info)
+
+ self._bundle_id = activity_info.get_bundle_id()
+ self._version = activity_info.get_activity_version()
+
+ registry = bundleregistry.get_registry()
+ self._favorite = registry.is_bundle_favorite(self._bundle_id,
+ self._version)
+
+ self._favorite_item = MenuItem('')
+ self._favorite_icon = Icon(icon_name='emblem-favorite',
+ icon_size=gtk.ICON_SIZE_MENU)
+ self._favorite_item.set_image(self._favorite_icon)
+ self._favorite_item.connect('activate',
+ self.__change_favorite_activate_cb)
+ self.menu.append(self._favorite_item)
+ self._favorite_item.show()
+
+ if activity_info.is_user_activity():
+ menu_item = MenuItem(_('Erase'), 'list-remove')
+ menu_item.connect('activate', self.__erase_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ if not os.access(activity_info.get_path(), os.W_OK):
+ menu_item.props.sensitive = False
+
+ registry = bundleregistry.get_registry()
+ self._activity_changed_sid = registry.connect('bundle_changed',
+ self.__activity_changed_cb)
+ self._update_favorite_item()
+
+ self.connect('destroy', self.__destroy_cb)
+
+ def __destroy_cb(self, palette):
+ self.disconnect(self._activity_changed_sid)
+
+ def _update_favorite_item(self):
+ label = self._favorite_item.child
+ if self._favorite:
+ label.set_text(_('Remove favorite'))
+ xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ else:
+ label.set_text(_('Make favorite'))
+ client = gconf.client_get_default()
+ xo_color = XoColor(client.get_string("/desktop/sugar/user/color"))
+
+ self._favorite_icon.props.xo_color = xo_color
+
+ def __change_favorite_activate_cb(self, menu_item):
+ registry = bundleregistry.get_registry()
+ registry.set_bundle_favorite(self._bundle_id,
+ self._version,
+ not self._favorite)
+
+ def __activity_changed_cb(self, activity_registry, activity_info):
+ if activity_info.get_bundle_id() == self._bundle_id and \
+ activity_info.get_activity_version() == self._version:
+ registry = bundleregistry.get_registry()
+ self._favorite = registry.is_bundle_favorite(self._bundle_id,
+ self._version)
+ self._update_favorite_item()
+
+ def __erase_activate_cb(self, menu_item):
+ self.emit('erase-activated', self._bundle_id)
+
diff --git a/shell/src/jarabe/desktop/favoriteslayout.py b/shell/src/jarabe/desktop/favoriteslayout.py
new file mode 100644
index 0000000..85e1b59
--- /dev/null
+++ b/shell/src/jarabe/desktop/favoriteslayout.py
@@ -0,0 +1,488 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import math
+import hashlib
+from gettext import gettext as _
+
+import gobject
+import gtk
+import hippo
+
+from sugar.graphics import style
+
+from jarabe.model import bundleregistry
+from jarabe.desktop.grid import Grid
+
+_logger = logging.getLogger('FavoritesLayout')
+
+_CELL_SIZE = 4
+_BASE_SCALE = 1000
+
+class FavoritesLayout(gobject.GObject, hippo.CanvasLayout):
+ """Base class of the different layout types."""
+
+ __gtype_name__ = 'FavoritesLayout'
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self.box = None
+ self.fixed_positions = {}
+
+ def do_set_box(self, box):
+ self.box = box
+
+ def do_get_height_request(self, for_width):
+ return 0, gtk.gdk.screen_height() - style.GRID_CELL_SIZE
+
+ def do_get_width_request(self):
+ return 0, gtk.gdk.screen_width()
+
+ def compare_activities(self, icon_a, icon_b):
+ return 0
+
+ def append(self, icon, locked=False):
+ if not hasattr(type(icon), 'fixed_position'):
+ logging.debug('Icon without fixed_position: %r', icon)
+ return
+
+ icon.props.size = max(icon.props.size, style.STANDARD_ICON_SIZE)
+
+ relative_x, relative_y = icon.fixed_position
+ if relative_x < 0 or relative_y < 0:
+ logging.debug('Icon out of bounds: %r', icon)
+ return
+
+ min_width_, width = self.box.get_width_request()
+ min_height_, height = self.box.get_height_request(width)
+ self.fixed_positions[icon] = \
+ (int(relative_x * _BASE_SCALE / float(width)),
+ int(relative_y * _BASE_SCALE / float(height)))
+
+ def remove(self, icon):
+ if icon in self.fixed_positions:
+ del self.fixed_positions[icon]
+
+ def move_icon(self, icon, x, y, locked=False):
+ if icon not in self.box.get_children():
+ raise ValueError('Child not in box.')
+
+ if not(hasattr(icon, 'get_bundle_id') and hasattr(icon, 'get_version')):
+ logging.debug('Not an activity icon %r', icon)
+ return
+
+ min_width_, width = self.box.get_width_request()
+ min_height_, height = self.box.get_height_request(width)
+ registry = bundleregistry.get_registry()
+ registry.set_bundle_position(
+ icon.get_bundle_id(), icon.get_version(),
+ x * width / float(_BASE_SCALE),
+ y * height / float(_BASE_SCALE))
+ self.fixed_positions[icon] = (x, y)
+
+ def do_allocate(self, x, y, width, height, req_width, req_height,
+ origin_changed):
+ raise NotImplementedError()
+
+ def allow_dnd(self):
+ return False
+
+class RandomLayout(FavoritesLayout):
+ """Lay out icons randomly; try to nudge them around to resolve overlaps."""
+
+ __gtype_name__ = 'RandomLayout'
+
+ icon_name = 'view-freeform'
+ """Name of icon used in home view dropdown palette."""
+
+ key = 'random-layout'
+ """String used in profile to represent this view."""
+
+ # TRANS: label for the freeform layout in the favorites view
+ palette_name = _('Freeform')
+ """String used to identify this layout in home view dropdown palette."""
+
+ def __init__(self):
+ FavoritesLayout.__init__(self)
+
+ min_width_, width = self.do_get_width_request()
+ min_height_, height = self.do_get_height_request(width)
+
+ self._grid = Grid(width / _CELL_SIZE, height / _CELL_SIZE)
+ self._grid.connect('child-changed', self.__grid_child_changed_cb)
+
+ def __grid_child_changed_cb(self, grid, child):
+ child.emit_request_changed()
+
+ def append(self, icon, locked=False):
+ FavoritesLayout.append(self, icon, locked)
+
+ min_width_, child_width = icon.get_width_request()
+ min_height_, child_height = icon.get_height_request(child_width)
+ min_width_, width = self.box.get_width_request()
+ min_height_, height = self.box.get_height_request(width)
+
+ if icon in self.fixed_positions:
+ x, y = self.fixed_positions[icon]
+ x = min(x, width - child_width)
+ y = min(y, height - child_height)
+ elif hasattr(icon, 'get_bundle_id'):
+ name_hash = hashlib.md5(icon.get_bundle_id())
+ x = int(name_hash.hexdigest()[:5], 16) % (width - child_width)
+ y = int(name_hash.hexdigest()[-5:], 16) % (height - child_height)
+ else:
+ x = None
+ y = None
+
+ if x is None or y is None:
+ self._grid.add(icon,
+ child_width / _CELL_SIZE, child_height / _CELL_SIZE)
+ else:
+ self._grid.add(icon,
+ child_width / _CELL_SIZE, child_height / _CELL_SIZE,
+ x / _CELL_SIZE, y / _CELL_SIZE)
+
+ def remove(self, icon):
+ self._grid.remove(icon)
+ FavoritesLayout.remove(self, icon)
+
+ def move_icon(self, icon, x, y, locked=False):
+ self._grid.move(icon, x / _CELL_SIZE, y / _CELL_SIZE, locked)
+ FavoritesLayout.move_icon(self, icon, x, y, locked)
+
+ def do_allocate(self, x, y, width, height, req_width, req_height,
+ origin_changed):
+ for child in self.box.get_layout_children():
+ # We need to always get requests to not confuse hippo
+ min_w_, child_width = child.get_width_request()
+ min_h_, child_height = child.get_height_request(child_width)
+
+ rect = self._grid.get_child_rect(child.item)
+ child.allocate(rect.x * _CELL_SIZE,
+ rect.y * _CELL_SIZE,
+ child_width,
+ child_height,
+ origin_changed)
+
+ def allow_dnd(self):
+ return True
+
+_MINIMUM_RADIUS = style.XLARGE_ICON_SIZE / 2 + style.DEFAULT_SPACING + \
+ style.STANDARD_ICON_SIZE * 2
+_MAXIMUM_RADIUS = (gtk.gdk.screen_height() - style.GRID_CELL_SIZE) / 2 - \
+ style.STANDARD_ICON_SIZE - style.DEFAULT_SPACING
+
+class RingLayout(FavoritesLayout):
+ """Lay out icons in a ring around the XO man."""
+
+ __gtype_name__ = 'RingLayout'
+ icon_name = 'view-radial'
+ """Name of icon used in home view dropdown palette."""
+ key = 'ring-layout'
+ """String used in profile to represent this view."""
+ # TRANS: label for the ring layout in the favorites view
+ palette_name = _('Ring')
+ """String used to identify this layout in home view dropdown palette."""
+
+ def __init__(self):
+ FavoritesLayout.__init__(self)
+ self._locked_children = {}
+
+ def append(self, icon, locked=False):
+ FavoritesLayout.append(self, icon, locked)
+ if locked:
+ child = self.box.find_box_child(icon)
+ self._locked_children[child] = (0, 0)
+
+ def remove(self, icon):
+ child = self.box.find_box_child(icon)
+ if child in self._locked_children:
+ del self._locked_children[child]
+ FavoritesLayout.remove(self, icon)
+
+ def move_icon(self, icon, x, y, locked=False):
+ FavoritesLayout.move_icon(self, icon, x, y, locked)
+ if locked:
+ child = self.box.find_box_child(icon)
+ self._locked_children[child] = (x, y)
+
+ def _calculate_radius_and_icon_size(self, children_count):
+ # what's the radius required without downscaling?
+ distance = style.STANDARD_ICON_SIZE + style.DEFAULT_SPACING
+ icon_size = style.STANDARD_ICON_SIZE
+ # circumference is 2*pi*r; we want this to be at least
+ # 'children_count * distance'
+ radius = children_count * distance / (2 * math.pi)
+ # limit computed radius to reasonable bounds.
+ radius = max(radius, _MINIMUM_RADIUS)
+ radius = min(radius, _MAXIMUM_RADIUS)
+ # recompute icon size from limited radius
+ if children_count > 0:
+ icon_size = (2 * math.pi * radius / children_count) \
+ - style.DEFAULT_SPACING
+ # limit adjusted icon size.
+ icon_size = max(icon_size, style.SMALL_ICON_SIZE)
+ icon_size = min(icon_size, style.MEDIUM_ICON_SIZE)
+ return radius, icon_size
+
+ def _calculate_position(self, radius, icon_size, index, children_count,
+ sin=math.sin, cos=math.cos):
+ width, height = self.box.get_allocation()
+ angle = index * (2 * math.pi / children_count) - math.pi / 2
+ x = radius * cos(angle) + (width - icon_size) / 2
+ y = radius * sin(angle) + (height - icon_size -
+ (style.GRID_CELL_SIZE/2) ) / 2
+ return x, y
+
+ def _get_children_in_ring(self):
+ children_in_ring = [child for child in self.box.get_layout_children() \
+ if child not in self._locked_children]
+ return children_in_ring
+
+ def do_allocate(self, x, y, width, height, req_width, req_height,
+ origin_changed):
+ children_in_ring = self._get_children_in_ring()
+ if children_in_ring:
+ radius, icon_size = \
+ self._calculate_radius_and_icon_size(len(children_in_ring))
+
+ for n in range(len(children_in_ring)):
+ child = children_in_ring[n]
+
+ x, y = self._calculate_position(radius, icon_size, n,
+ len(children_in_ring))
+
+ # We need to always get requests to not confuse hippo
+ min_w_, child_width = child.get_width_request()
+ min_h_, child_height = child.get_height_request(child_width)
+
+ child.allocate(int(x), int(y), child_width, child_height,
+ origin_changed)
+ child.item.props.size = icon_size
+
+ for child in self._locked_children.keys():
+ x, y = self._locked_children[child]
+
+ # We need to always get requests to not confuse hippo
+ min_w_, child_width = child.get_width_request()
+ min_h_, child_height = child.get_height_request(child_width)
+
+ if child_width <= 0 or child_height <= 0:
+ return
+
+ child.allocate(int(x), int(y), child_width, child_height,
+ origin_changed)
+
+ def compare_activities(self, icon_a, icon_b):
+ if hasattr(icon_a, 'installation_time') and \
+ hasattr(icon_b, 'installation_time'):
+ return icon_b.installation_time - icon_a.installation_time
+ else:
+ return 0
+
+_SUNFLOWER_CONSTANT = style.STANDARD_ICON_SIZE * .75
+"""Chose a constant such that STANDARD_ICON_SIZE icons are nicely spaced."""
+
+_SUNFLOWER_OFFSET = \
+ math.pow((style.XLARGE_ICON_SIZE / 2 + style.STANDARD_ICON_SIZE) /
+ _SUNFLOWER_CONSTANT, 2)
+"""
+Compute a starting index for the `SunflowerLayout` which leaves space for
+the XO man in the center. Since r = _SUNFLOWER_CONSTANT * sqrt(n),
+solve for n when r is (XLARGE_ICON_SIZE + STANDARD_ICON_SIZE)/2.
+"""
+
+_GOLDEN_RATIO = 1.6180339887498949
+"""
+Golden ratio: http://en.wikipedia.org/wiki/Golden_ratio
+Calculation: (math.sqrt(5) + 1) / 2
+"""
+
+_SUNFLOWER_ANGLE = 2.3999632297286531
+"""
+The sunflower angle is approximately 137.5 degrees.
+This is the golden angle: http://en.wikipedia.org/wiki/Golden_angle
+Calculation: math.radians(360) / ( _GOLDEN_RATIO * _GOLDEN_RATIO )
+"""
+
+class SunflowerLayout(RingLayout):
+ """Spiral layout based on Fibonacci ratio in phyllotaxis.
+
+ See http://algorithmicbotany.org/papers/abop/abop-ch4.pdf
+ for details of Vogel's model of florets in a sunflower head."""
+
+ __gtype_name__ = 'SunflowerLayout'
+
+ icon_name = 'view-spiral'
+ """Name of icon used in home view dropdown palette."""
+
+ key = 'spiral-layout'
+ """String used in profile to represent this view."""
+
+ # TRANS: label for the spiral layout in the favorites view
+ palette_name = _('Spiral')
+ """String used to identify this layout in home view dropdown palette."""
+
+ def __init__(self):
+ RingLayout.__init__(self)
+ self.skipped_indices = []
+
+ def _calculate_radius_and_icon_size(self, children_count):
+ """Stub out this method; not used in `SunflowerLayout`."""
+ return None, style.STANDARD_ICON_SIZE
+
+ def adjust_index(self, i):
+ """Skip floret indices which end up outside the desired bounding box."""
+ for idx in self.skipped_indices:
+ if i < idx:
+ break
+ i += 1
+ return i
+
+ def _calculate_position(self, radius, icon_size, oindex, children_count,
+ sin=math.sin, cos=math.cos):
+ """Calculate the position of sunflower floret number 'oindex'.
+ If the result is outside the bounding box, use the next index which
+ is inside the bounding box."""
+
+ width, height = self.box.get_allocation()
+
+ while True:
+
+ index = self.adjust_index(oindex)
+
+ # tweak phi to get a nice gap lined up where the "active activity"
+ # icon is, below the central XO man.
+ phi = index * _SUNFLOWER_ANGLE + math.radians(-130)
+
+ # we offset index when computing r to make space for the XO man.
+ r = _SUNFLOWER_CONSTANT * math.sqrt(index + _SUNFLOWER_OFFSET)
+
+ # x,y are the top-left corner of the icon, so remove icon_size
+ # from width/height to compensate. y has an extra GRID_CELL_SIZE/2
+ # removed to make room for the "active activity" icon.
+ x = r * cos(phi) + (width - icon_size) / 2
+ y = r * sin(phi) + (height - icon_size - \
+ (style.GRID_CELL_SIZE / 2) ) / 2
+
+ # skip allocations outside the allocation box.
+ # give up once we can't fit
+ if r < math.hypot(width / 2, height / 2):
+ if y < 0 or y > (height - icon_size) or \
+ x < 0 or x > (width - icon_size):
+ self.skipped_indices.append(index)
+ continue # try again
+
+ return x, y
+
+class BoxLayout(RingLayout):
+ """Lay out icons in a square around the XO man."""
+
+ __gtype_name__ = 'BoxLayout'
+
+ icon_name = 'view-box'
+ """Name of icon used in home view dropdown palette."""
+
+ key = 'box-layout'
+ """String used in profile to represent this view."""
+
+ # TRANS: label for the box layout in the favorites view
+ palette_name = _('Box')
+ """String used to identify this layout in home view dropdown palette."""
+
+ def __init__(self):
+ RingLayout.__init__(self)
+
+ def _calculate_position(self, radius, icon_size, index, children_count,
+ sin=None, cos=None):
+
+ # use "orthogonal" versions of cos and sin in order to square the
+ # circle and turn the 'ring view' into a 'box view'
+ def cos_d(d):
+ while d < 0:
+ d += 360
+ if d < 45:
+ return 1
+ if d < 135:
+ return (90 - d) / 45.
+ if d < 225:
+ return -1
+ return cos_d(360 - d) # mirror around 180
+
+ cos = lambda r: cos_d(math.degrees(r))
+ sin = lambda r: cos_d(math.degrees(r) - 90)
+
+ return RingLayout._calculate_position\
+ (self, radius, icon_size, index, children_count,
+ sin=sin, cos=cos)
+
+class TriangleLayout(RingLayout):
+ """Lay out icons in a triangle around the XO man."""
+
+ __gtype_name__ = 'TriangleLayout'
+
+ icon_name = 'view-triangle'
+ """Name of icon used in home view dropdown palette."""
+
+ key = 'triangle-layout'
+ """String used in profile to represent this view."""
+
+ # TRANS: label for the box layout in the favorites view
+ palette_name = _('Triangle')
+ """String used to identify this layout in home view dropdown palette."""
+
+ def __init__(self):
+ RingLayout.__init__(self)
+
+ def _calculate_radius_and_icon_size(self, children_count):
+ # use slightly larger minimum radius than parent, because sides
+ # of triangle come awful close to the center.
+ radius, icon_size = \
+ RingLayout._calculate_radius_and_icon_size(self, children_count)
+ return max(radius, _MINIMUM_RADIUS + style.MEDIUM_ICON_SIZE), icon_size
+
+ def _calculate_position(self, radius, icon_size, index, children_count,
+ sin=math.sin, cos=math.cos):
+ # tweak cos and sin in order to make the 'ring' into an equilateral
+ # triangle.
+
+ def cos_d(d):
+ while d < -90:
+ d += 360
+ if d <= 30:
+ return (d + 90) / 120.
+ if d <= 90:
+ return (90 - d) / 60.
+ return -cos_d(180 - d) # mirror around 90
+
+ sqrt_3 = math.sqrt(3)
+
+ def sin_d(d):
+ while d < -90:
+ d += 360
+ if d <= 30:
+ return ((d + 90) / 120.) * sqrt_3 - 1
+ if d <= 90:
+ return sqrt_3 - 1
+ return sin_d(180 - d) # mirror around 90
+
+ cos = lambda r: cos_d(math.degrees(r))
+ sin = lambda r: sin_d(math.degrees(r))
+
+ return RingLayout._calculate_position\
+ (self, radius, icon_size, index, children_count,
+ sin=sin, cos=cos)
diff --git a/shell/src/jarabe/desktop/favoritesview.py b/shell/src/jarabe/desktop/favoritesview.py
new file mode 100644
index 0000000..bb85024
--- /dev/null
+++ b/shell/src/jarabe/desktop/favoritesview.py
@@ -0,0 +1,670 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+import math
+
+import gobject
+import gconf
+import gtk
+import hippo
+
+from sugar.graphics import style
+from sugar.graphics.icon import Icon, CanvasIcon
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.alert import Alert
+from sugar.graphics.xocolor import XoColor
+from sugar.activity import activityfactory
+from sugar.activity.activityhandle import ActivityHandle
+from sugar.presence import presenceservice
+from sugar import dispatch
+from sugar.datastore import datastore
+
+from jarabe.view.palettes import JournalPalette
+from jarabe.view.palettes import CurrentActivityPalette, ActivityPalette
+from jarabe.view.buddyicon import BuddyIcon
+from jarabe.view.buddymenu import BuddyMenu
+from jarabe.view import launcher
+from jarabe.model.buddy import BuddyModel, get_owner_instance
+from jarabe.model import shell
+from jarabe.model import bundleregistry
+from jarabe.journal import misc
+
+from jarabe.desktop import schoolserver
+from jarabe.desktop.schoolserver import RegisterError
+from jarabe.desktop import favoriteslayout
+
+_logger = logging.getLogger('FavoritesView')
+
+_ICON_DND_TARGET = ('activity-icon', gtk.TARGET_SAME_WIDGET, 0)
+
+LAYOUT_MAP = {favoriteslayout.RingLayout.key: favoriteslayout.RingLayout,
+ #favoriteslayout.BoxLayout.key: favoriteslayout.BoxLayout,
+ #favoriteslayout.TriangleLayout.key: favoriteslayout.TriangleLayout,
+ #favoriteslayout.SunflowerLayout.key: favoriteslayout.SunflowerLayout,
+ favoriteslayout.RandomLayout.key: favoriteslayout.RandomLayout}
+"""Map numeric layout identifiers to uninstantiated subclasses of
+`FavoritesLayout` which implement the layouts. Additional information
+about the layout can be accessed with fields of the class."""
+
+class FavoritesView(hippo.Canvas):
+ __gtype_name__ = 'SugarFavoritesView'
+
+ def __init__(self, **kwargs):
+ logging.debug('STARTUP: Loading the favorites view')
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ # DND stuff
+ self._pressed_button = None
+ self._press_start_x = None
+ self._press_start_y = None
+ self._hot_x = None
+ self._hot_y = None
+ self._last_clicked_icon = None
+
+ self._box = hippo.CanvasBox()
+ self._box.props.background_color = style.COLOR_WHITE.get_int()
+ self.set_root(self._box)
+
+ self._my_icon = OwnerIcon(style.XLARGE_ICON_SIZE)
+ self._my_icon.connect('register-activate', self.__register_activate_cb)
+ self._box.append(self._my_icon)
+
+ self._current_activity = CurrentActivityIcon()
+ self._box.append(self._current_activity)
+
+ self._layout = None
+ self._alert = None
+ self._resume_mode = True
+
+ # More DND stuff
+ self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
+ gtk.gdk.POINTER_MOTION_HINT_MASK)
+ self.connect('motion-notify-event', self.__motion_notify_event_cb)
+ self.connect('button-press-event', self.__button_press_event_cb)
+ self.connect('drag-begin', self.__drag_begin_cb)
+ self.connect('drag-motion', self.__drag_motion_cb)
+ self.connect('drag-drop', self.__drag_drop_cb)
+ self.connect('drag-data-received', self.__drag_data_received_cb)
+
+ gobject.idle_add(self.__connect_to_bundle_registry_cb)
+
+ favorites_settings = get_settings()
+ favorites_settings.changed.connect(self.__settings_changed_cb)
+ self._set_layout(favorites_settings.layout)
+
+ def __settings_changed_cb(self, **kwargs):
+ favorites_settings = get_settings()
+ self._set_layout(favorites_settings.layout)
+
+ def __connect_to_bundle_registry_cb(self):
+ registry = bundleregistry.get_registry()
+
+ for info in registry:
+ if registry.is_bundle_favorite(info.get_bundle_id(),
+ info.get_activity_version()):
+ self._add_activity(info)
+
+ registry.connect('bundle-added', self.__activity_added_cb)
+ registry.connect('bundle-removed', self.__activity_removed_cb)
+ registry.connect('bundle-changed', self.__activity_changed_cb)
+
+ def _add_activity(self, activity_info):
+ if activity_info.get_bundle_id() == 'org.laptop.JournalActivity':
+ return
+ icon = ActivityIcon(activity_info)
+ icon.props.size = style.STANDARD_ICON_SIZE
+ icon.set_resume_mode(self._resume_mode)
+ self._box.insert_sorted(icon, 0, self._layout.compare_activities)
+ self._layout.append(icon)
+
+ def __activity_added_cb(self, activity_registry, activity_info):
+ registry = bundleregistry.get_registry()
+ if registry.is_bundle_favorite(activity_info.get_bundle_id(),
+ activity_info.get_activity_version()):
+ self._add_activity(activity_info)
+
+ def _find_activity_icon(self, bundle_id, version):
+ for icon in self._box.get_children():
+ if isinstance(icon, ActivityIcon) and \
+ icon.bundle_id == bundle_id and icon.version == version:
+ return icon
+ return None
+
+ def __activity_removed_cb(self, activity_registry, activity_info):
+ icon = self._find_activity_icon(activity_info.get_bundle_id(),
+ activity_info.get_activity_version())
+ if icon is not None:
+ self._layout.remove(icon)
+ self._box.remove(icon)
+
+ def __activity_changed_cb(self, activity_registry, activity_info):
+ if activity_info.get_bundle_id() == 'org.laptop.JournalActivity':
+ return
+ icon = self._find_activity_icon(activity_info.get_bundle_id(),
+ activity_info.get_activity_version())
+ if icon is not None:
+ self._box.remove(icon)
+
+ registry = bundleregistry.get_registry()
+ if registry.is_bundle_favorite(activity_info.get_bundle_id(),
+ activity_info.get_activity_version()):
+ self._add_activity(activity_info)
+
+ def do_size_allocate(self, allocation):
+ width = allocation.width
+ height = allocation.height
+
+ min_w_, my_icon_width = self._my_icon.get_width_request()
+ min_h_, my_icon_height = self._my_icon.get_height_request(my_icon_width)
+ x = (width - my_icon_width) / 2
+ y = (height - my_icon_height - style.GRID_CELL_SIZE) / 2
+ self._layout.move_icon(self._my_icon, x, y, locked=True)
+
+ min_w_, icon_width = self._current_activity.get_width_request()
+ min_h_, icon_height = \
+ self._current_activity.get_height_request(icon_width)
+ x = (width - icon_width) / 2
+ y = (height - my_icon_height - style.GRID_CELL_SIZE) / 2 + \
+ my_icon_height + style.DEFAULT_PADDING
+ self._layout.move_icon(self._current_activity, x, y, locked=True)
+
+ hippo.Canvas.do_size_allocate(self, allocation)
+
+ # TODO: Dnd methods. This should be merged somehow inside hippo-canvas.
+ def __button_press_event_cb(self, widget, event):
+ if event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS:
+ self._last_clicked_icon = self._get_icon_at_coords(event.x, event.y)
+ if self._last_clicked_icon is not None:
+ self._pressed_button = event.button
+ self._press_start_x = event.x
+ self._press_start_y = event.y
+
+ return False
+
+ def _get_icon_at_coords(self, x, y):
+ for icon in self._box.get_children():
+ icon_x, icon_y = icon.get_context().translate_to_widget(icon)
+ icon_width, icon_height = icon.get_allocation()
+
+ if (x >= icon_x ) and (x <= icon_x + icon_width) and \
+ (y >= icon_y ) and (y <= icon_y + icon_height) and \
+ isinstance(icon, ActivityIcon):
+ return icon
+ return None
+
+ def __motion_notify_event_cb(self, widget, event):
+ if not self._pressed_button:
+ return False
+
+ # if the mouse button is not pressed, no drag should occurr
+ if not event.state & gtk.gdk.BUTTON1_MASK:
+ self._pressed_button = None
+ return False
+
+ if event.is_hint:
+ x, y, state_ = event.window.get_pointer()
+ else:
+ x = event.x
+ y = event.y
+
+ if widget.drag_check_threshold(int(self._press_start_x),
+ int(self._press_start_y),
+ int(x),
+ int(y)):
+ context_ = widget.drag_begin([_ICON_DND_TARGET],
+ gtk.gdk.ACTION_MOVE,
+ 1,
+ event)
+ return False
+
+ def __drag_begin_cb(self, widget, context):
+ icon_file_name = self._last_clicked_icon.props.file_name
+ # TODO: we should get the pixbuf from the widget, so it has colors, etc
+ pixbuf = gtk.gdk.pixbuf_new_from_file(icon_file_name)
+
+ self._hot_x = pixbuf.props.width / 2
+ self._hot_y = pixbuf.props.height / 2
+ context.set_icon_pixbuf(pixbuf, self._hot_x, self._hot_y)
+
+ def __drag_motion_cb(self, widget, context, x, y, time):
+ if self._last_clicked_icon is not None:
+ context.drag_status(context.suggested_action, time)
+ return True
+ else:
+ return False
+
+ def __drag_drop_cb(self, widget, context, x, y, time):
+ if self._last_clicked_icon is not None:
+ self.drag_get_data(context, _ICON_DND_TARGET[0])
+
+ self._layout.move_icon(self._last_clicked_icon,
+ x - self._hot_x, y - self._hot_y)
+
+ self._pressed_button = None
+ self._press_start_x = None
+ self._press_start_y = None
+ self._hot_x = None
+ self._hot_y = None
+ self._last_clicked_icon = None
+
+ return True
+ else:
+ return False
+
+ def __drag_data_received_cb(self, widget, context, x, y, selection_data,
+ info, time):
+ context.drop_finish(success=True, time=time)
+
+ def _set_layout(self, layout):
+ if layout not in LAYOUT_MAP:
+ logging.warn('Unknown favorites layout: %r' % layout)
+ layout = favoriteslayout.RingLayout.key
+ assert layout in LAYOUT_MAP
+
+ if type(self._layout) == LAYOUT_MAP[layout]:
+ return
+
+ self._layout = LAYOUT_MAP[layout]()
+ self._box.set_layout(self._layout)
+
+ #TODO: compatibility hack while sort() gets added to the hippo python
+ # bindings
+ if hasattr(self._box, 'sort'):
+ self._box.sort(self._layout.compare_activities)
+
+ for icon in self._box.get_children():
+ if icon not in [self._my_icon, self._current_activity]:
+ self._layout.append(icon)
+
+ self._layout.append(self._my_icon, locked=True)
+ self._layout.append(self._current_activity, locked=True)
+
+ if self._layout.allow_dnd():
+ self.drag_source_set(0, [], 0)
+ self.drag_dest_set(0, [], 0)
+ else:
+ self.drag_source_unset()
+ self.drag_dest_unset()
+
+ layout = property(None, _set_layout)
+
+ def add_alert(self, alert):
+ if self._alert is not None:
+ self.remove_alert()
+ alert.set_size_request(gtk.gdk.screen_width(), -1)
+ self._alert = hippo.CanvasWidget(widget=alert)
+ self._box.append(self._alert, hippo.PACK_FIXED)
+
+ def remove_alert(self):
+ self._box.remove(self._alert)
+ self._alert = None
+
+ def __register_activate_cb(self, icon):
+ alert = Alert()
+ try:
+ schoolserver.register_laptop()
+ except RegisterError, e:
+ alert.props.title = _('Registration Failed')
+ alert.props.msg = _('%s') % e
+ else:
+ alert.props.title = _('Registration Successful')
+ alert.props.msg = _('You are now registered ' \
+ 'with your school server.')
+ self._my_icon.remove_register_menu()
+
+ ok_icon = Icon(icon_name='dialog-ok')
+ alert.add_button(gtk.RESPONSE_OK, _('Ok'), ok_icon)
+
+ self.add_alert(alert)
+ alert.connect('response', self.__register_alert_response_cb)
+
+ def __register_alert_response_cb(self, alert, response_id):
+ self.remove_alert()
+
+ def set_resume_mode(self, resume_mode):
+ self._resume_mode = resume_mode
+ for icon in self._box.get_children():
+ if hasattr(icon, 'set_resume_mode'):
+ icon.set_resume_mode(self._resume_mode)
+
+
+class ActivityIcon(CanvasIcon):
+ __gtype_name__ = 'SugarFavoriteActivityIcon'
+
+ _BORDER_WIDTH = style.zoom(3)
+ _MAX_RESUME_ENTRIES = 5
+
+ def __init__(self, activity_info):
+ CanvasIcon.__init__(self, cache=True,
+ file_name=activity_info.get_icon())
+
+ self._activity_info = activity_info
+ self._journal_entries = []
+ self._hovering = False
+ self._resume_mode = True
+
+ self.connect('hovering-changed', self.__hovering_changed_event_cb)
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ datastore.updated.connect(self.__datastore_listener_updated_cb)
+ datastore.deleted.connect(self.__datastore_listener_deleted_cb)
+
+ self._refresh()
+ self._update()
+
+ def _refresh(self):
+ bundle_id = self._activity_info.get_bundle_id()
+ properties = ['uid', 'title', 'icon-color', 'activity', 'activity_id',
+ 'mime_type', 'mountpoint']
+ self._get_last_activity_async(bundle_id, properties)
+
+ def __datastore_listener_updated_cb(self, **kwargs):
+ bundle_id = self._activity_info.get_bundle_id()
+ if kwargs['metadata'].get('activity', '') == bundle_id:
+ self._refresh()
+
+ def __datastore_listener_deleted_cb(self, **kwargs):
+ for entry in self._journal_entries:
+ if entry['uid'] == kwargs['object_id']:
+ self._refresh()
+ break
+
+ def _get_last_activity_async(self, bundle_id, properties):
+ query = {'activity': bundle_id}
+ datastore.find(query, sorting=['+timestamp'],
+ limit=self._MAX_RESUME_ENTRIES,
+ properties=properties,
+ reply_handler=self.__get_last_activity_reply_handler_cb,
+ error_handler=self.__get_last_activity_error_handler_cb)
+
+ def __get_last_activity_reply_handler_cb(self, entries, total_count):
+ # If there's a problem with the DS index, we may get entries not related
+ # to this activity.
+ checked_entries = []
+ for entry in entries:
+ if entry['activity'] == self.bundle_id:
+ checked_entries.append(entry)
+
+ self._journal_entries = checked_entries
+ self._update()
+
+ def __get_last_activity_error_handler_cb(self, error):
+ logging.error('Error retrieving most recent activities: %r', error)
+
+ def _update(self):
+ self.palette = None
+ if not self._resume_mode or not self._journal_entries:
+ xo_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ else:
+ xo_color = misc.get_icon_color(self._journal_entries[0])
+ self.props.xo_color = xo_color
+
+ def create_palette(self):
+ palette = FavoritePalette(self._activity_info, self._journal_entries)
+ palette.connect('activate', self.__palette_activate_cb)
+ palette.connect('entry-activate', self.__palette_entry_activate_cb)
+ return palette
+
+ def __palette_activate_cb(self, palette):
+ self._activate()
+
+ def __palette_entry_activate_cb(self, palette, metadata):
+ self._resume(metadata)
+
+ def __hovering_changed_event_cb(self, icon, hovering):
+ self._hovering = hovering
+ self.emit_paint_needed(0, 0, -1, -1)
+
+ def do_paint_above_children(self, cr, damaged_box):
+ if not self._hovering:
+ return
+
+ width, height = self.get_allocation()
+
+ x = ActivityIcon._BORDER_WIDTH / 2.0
+ y = ActivityIcon._BORDER_WIDTH / 2.0
+ width -= ActivityIcon._BORDER_WIDTH
+ height -= ActivityIcon._BORDER_WIDTH
+ radius = width / 10.0
+
+ cr.move_to(x + radius, y)
+ cr.arc(x + width - radius, y + radius, radius, math.pi * 1.5,
+ math.pi * 2.0)
+ cr.arc(x + width - radius, x + height - radius, radius, 0,
+ math.pi * 0.5)
+ cr.arc(x + radius, y + height - radius, radius, math.pi * 0.5, math.pi)
+ cr.arc(x + radius, y + radius, radius, math.pi, math.pi * 1.5)
+
+ color = style.COLOR_SELECTION_GREY.get_int()
+ hippo.cairo_set_source_rgba32(cr, color)
+ cr.set_line_width(ActivityIcon._BORDER_WIDTH)
+ cr.stroke()
+
+ def do_get_content_height_request(self, for_width):
+ height, height = CanvasIcon.do_get_content_height_request(self,
+ for_width)
+ height += ActivityIcon._BORDER_WIDTH * 2
+ return height, height
+
+ def do_get_content_width_request(self):
+ width, width = CanvasIcon.do_get_content_width_request(self)
+ width += ActivityIcon._BORDER_WIDTH * 2
+ return width, width
+
+ def __button_release_event_cb(self, icon, event):
+ self._activate()
+
+ def _resume(self, journal_entry):
+ if not journal_entry['activity_id']:
+ journal_entry['activity_id'] = activityfactory.create_activity_id()
+ misc.resume(journal_entry, self._activity_info.get_bundle_id())
+
+ def _activate(self):
+ if self.palette is not None:
+ self.palette.popdown(immediate=True)
+
+ if self._resume_mode and self._journal_entries:
+ self._resume(self._journal_entries[0])
+ else:
+ misc.launch(self._activity_info)
+
+ def get_bundle_id(self):
+ return self._activity_info.get_bundle_id()
+ bundle_id = property(get_bundle_id, None)
+
+ def get_version(self):
+ return self._activity_info.get_activity_version()
+ version = property(get_version, None)
+
+ def _get_installation_time(self):
+ return self._activity_info.get_installation_time()
+ installation_time = property(_get_installation_time, None)
+
+ def _get_fixed_position(self):
+ registry = bundleregistry.get_registry()
+ return registry.get_bundle_position(self.bundle_id, self.version)
+ fixed_position = property(_get_fixed_position, None)
+
+ def set_resume_mode(self, resume_mode):
+ self._resume_mode = resume_mode
+ self._update()
+
+class FavoritePalette(ActivityPalette):
+ __gtype_name__ = 'SugarFavoritePalette'
+
+ __gsignals__ = {
+ 'entry-activate': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ }
+
+ def __init__(self, activity_info, journal_entries):
+ ActivityPalette.__init__(self, activity_info)
+
+ if not journal_entries:
+ xo_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ else:
+ xo_color = misc.get_icon_color(journal_entries[0])
+
+ self.props.icon = Icon(file=activity_info.get_icon(),
+ xo_color=xo_color,
+ icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
+
+ if journal_entries:
+ self.props.secondary_text = journal_entries[0]['title']
+
+ menu_items = []
+ for entry in journal_entries:
+ icon_file_name = misc.get_icon_name(entry)
+ color = misc.get_icon_color(entry)
+
+ menu_item = MenuItem(text_label=entry['title'],
+ file_name=icon_file_name,
+ xo_color=color)
+ menu_item.connect('activate', self.__resume_entry_cb, entry)
+ menu_items.append(menu_item)
+ menu_item.show()
+
+ if journal_entries:
+ separator = gtk.SeparatorMenuItem()
+ menu_items.append(separator)
+ separator.show()
+
+ for i in range(0, len(menu_items)):
+ self.menu.insert(menu_items[i], i)
+
+ def __resume_entry_cb(self, menu_item, entry):
+ if entry is not None:
+ self.emit('entry-activate', entry)
+
+class CurrentActivityIcon(CanvasIcon, hippo.CanvasItem):
+ def __init__(self):
+ CanvasIcon.__init__(self, cache=True)
+ self._home_model = shell.get_model()
+ self._home_activity = self._home_model.get_active_activity()
+
+ if self._home_activity is not None:
+ self._update()
+
+ self._home_model.connect('active-activity-changed',
+ self.__active_activity_changed_cb)
+
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ def __button_release_event_cb(self, icon, event):
+ window = self._home_model.get_active_activity().get_window()
+ window.activate(gtk.get_current_event_time())
+
+ def _update(self):
+ self.props.file_name = self._home_activity.get_icon_path()
+ self.props.xo_color = self._home_activity.get_icon_color()
+ self.props.size = style.STANDARD_ICON_SIZE
+
+ if self.palette is not None:
+ self.palette.destroy()
+ self.palette = None
+
+ def create_palette(self):
+ if self._home_activity.is_journal():
+ palette = JournalPalette(self._home_activity)
+ else:
+ palette = CurrentActivityPalette(self._home_activity)
+ return palette
+
+ def __active_activity_changed_cb(self, home_model, home_activity):
+ self._home_activity = home_activity
+ self._update()
+
+class OwnerIcon(BuddyIcon):
+ __gtype_name__ = 'SugarFavoritesOwnerIcon'
+
+ __gsignals__ = {
+ 'register-activate' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([]))
+ }
+ def __init__(self, size):
+ BuddyIcon.__init__(self, buddy=get_owner_instance(), size=size)
+
+ self._palette_enabled = False
+ self._register_menu = None
+
+ def create_palette(self):
+ if not self._palette_enabled:
+ self._palette_enabled = True
+ return
+
+ presence_service = presenceservice.get_instance()
+ palette = BuddyMenu(self.buddy)
+
+ client = gconf.client_get_default()
+ backup_url = client.get_string('/desktop/sugar/backup_url')
+ if not backup_url:
+ self._register_menu = MenuItem(_('Register'), 'media-record')
+ self._register_menu.connect('activate', self.__register_activate_cb)
+ palette.menu.append(self._register_menu)
+ self._register_menu.show()
+
+ return palette
+
+ def get_toplevel(self):
+ return hippo.get_canvas_for_item(self).get_toplevel()
+
+ def __register_activate_cb(self, menuitem):
+ self.emit('register-activate')
+
+ def remove_register_menu(self):
+ self.palette.menu.remove(self._register_menu)
+
+class FavoritesSetting(object):
+
+ _FAVORITES_KEY = "/desktop/sugar/desktop/favorites_layout"
+
+ def __init__(self):
+ client = gconf.client_get_default()
+ self._layout = client.get_string(self._FAVORITES_KEY)
+ logging.debug('FavoritesSetting layout %r', self._layout)
+
+ self._mode = None
+
+ self.changed = dispatch.Signal()
+
+ def get_layout(self):
+ return self._layout
+
+ def set_layout(self, layout):
+ logging.debug('set_layout %r %r', layout, self._layout)
+ if layout != self._layout:
+ self._layout = layout
+
+ client = gconf.client_get_default()
+ client.set_string(self._FAVORITES_KEY, layout)
+
+ self.changed.send(self)
+
+ layout = property(get_layout, set_layout)
+
+_favorites_settings = None
+
+def get_settings():
+ global _favorites_settings
+ if _favorites_settings is None:
+ _favorites_settings = FavoritesSetting()
+ return _favorites_settings
diff --git a/shell/src/jarabe/desktop/friendview.py b/shell/src/jarabe/desktop/friendview.py
new file mode 100644
index 0000000..c3faef8
--- /dev/null
+++ b/shell/src/jarabe/desktop/friendview.py
@@ -0,0 +1,87 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import hippo
+
+from sugar.graphics.icon import CanvasIcon
+from sugar.graphics import style
+from sugar.presence import presenceservice
+
+from jarabe.view.buddyicon import BuddyIcon
+from jarabe.model import bundleregistry
+
+class FriendView(hippo.CanvasBox):
+ def __init__(self, buddy, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
+
+ self._pservice = presenceservice.get_instance()
+
+ self._buddy = buddy
+ self._buddy_icon = BuddyIcon(buddy)
+ self._buddy_icon.props.size = style.LARGE_ICON_SIZE
+ self.append(self._buddy_icon)
+
+ self._activity_icon = CanvasIcon(size=style.LARGE_ICON_SIZE)
+ self._activity_icon_visible = False
+
+ self._update_activity()
+
+ self._buddy.connect('notify::current-activity',
+ self.__buddy_notify_current_activity_cb)
+ self._buddy.connect('notify::present', self.__buddy_notify_present_cb)
+ self._buddy.connect('notify::color', self.__buddy_notify_color_cb)
+
+ def _get_new_icon_name(self, ps_activity):
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(ps_activity.props.type)
+ if activity_info:
+ return activity_info.get_icon()
+ return None
+
+ def _remove_activity_icon(self):
+ if self._activity_icon_visible:
+ self.remove(self._activity_icon)
+ self._activity_icon_visible = False
+
+ def __buddy_notify_current_activity_cb(self, buddy, pspec):
+ self._update_activity()
+
+ def _update_activity(self):
+ if not self._buddy.props.present or \
+ not self._buddy.props.current_activity:
+ self._remove_activity_icon()
+ return
+
+ # FIXME: use some sort of "unknown activity" icon rather
+ # than hiding the icon?
+ name = self._get_new_icon_name(self._buddy.current_activity)
+ if name:
+ self._activity_icon.props.file_name = name
+ self._activity_icon.props.xo_color = self._buddy.props.color
+ if not self._activity_icon_visible:
+ self.append(self._activity_icon, hippo.PACK_EXPAND)
+ self._activity_icon_visible = True
+ else:
+ self._remove_activity_icon()
+
+ def __buddy_notify_present_cb(self, buddy, pspec):
+ self._update_activity()
+
+ def __buddy_notify_color_cb(self, buddy, pspec):
+ # TODO: shouldn't this change self._buddy_icon instead?
+ self._activity_icon.props.xo_color = buddy.props.color
+
diff --git a/shell/src/jarabe/desktop/grid.py b/shell/src/jarabe/desktop/grid.py
new file mode 100644
index 0000000..f3412c9
--- /dev/null
+++ b/shell/src/jarabe/desktop/grid.py
@@ -0,0 +1,201 @@
+# Copyright (C) 2007 Red Hat, Inc.
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import random
+
+import gobject
+import gtk
+
+from sugar import _sugarext
+
+_PLACE_TRIALS = 20
+_MAX_WEIGHT = 255
+_REFRESH_RATE = 200
+_MAX_COLLISIONS_PER_REFRESH = 20
+
+class Grid(_sugarext.Grid):
+ __gsignals__ = {
+ 'child-changed' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+ def __init__(self, width, height):
+ gobject.GObject.__init__(self)
+
+ self.width = width
+ self.height = height
+ self._children = []
+ self._child_rects = {}
+ self._locked_children = set()
+ self._collisions = []
+ self._collisions_sid = 0
+
+ self.setup(self.width, self.height)
+
+ def add(self, child, width, height, x=None, y=None, locked=False):
+ if x is not None and y is not None:
+ rect = gtk.gdk.Rectangle(x, y, width, height)
+ weight = self.compute_weight(rect)
+ else:
+ trials = _PLACE_TRIALS
+ weight = _MAX_WEIGHT
+ while trials > 0 and weight:
+ x = int(random.random() * (self.width - width))
+ y = int(random.random() * (self.height - height))
+
+ rect = gtk.gdk.Rectangle(x, y, width, height)
+ new_weight = self.compute_weight(rect)
+ if weight > new_weight:
+ weight = new_weight
+
+ trials -= 1
+
+ self._child_rects[child] = rect
+ self._children.append(child)
+ self.add_weight(self._child_rects[child])
+ if locked:
+ self._locked_children.add(child)
+
+ if weight > 0:
+ self._detect_collisions(child)
+
+ def remove(self, child):
+ self._children.remove(child)
+ self.remove_weight(self._child_rects[child])
+ self._locked_children.discard(child)
+ del self._child_rects[child]
+
+ if child in self._collisions:
+ self._collisions.remove(child)
+
+ def move(self, child, x, y, locked=False):
+ self.remove_weight(self._child_rects[child])
+
+ rect = self._child_rects[child]
+ rect.x = x
+ rect.y = y
+
+ weight = self.compute_weight(rect)
+ self.add_weight(self._child_rects[child])
+
+ if locked:
+ self._locked_children.add(child)
+ else:
+ self._locked_children.discard(child)
+
+ if weight > 0:
+ self._detect_collisions(child)
+
+ def _shift_child(self, child, weight):
+ rect = self._child_rects[child]
+
+ new_rects = []
+
+ # Get rects right, left, bottom and top
+ if (rect.x + rect.width < self.width - 1):
+ new_rects.append(gtk.gdk.Rectangle(rect.x + 1, rect.y,
+ rect.width, rect.height))
+
+ if (rect.x - 1 > 0):
+ new_rects.append(gtk.gdk.Rectangle(rect.x - 1, rect.y,
+ rect.width, rect.height))
+
+ if (rect.y + rect.height < self.height - 1):
+ new_rects.append(gtk.gdk.Rectangle(rect.x, rect.y + 1,
+ rect.width, rect.height))
+
+ if (rect.y - 1 > 0):
+ new_rects.append(gtk.gdk.Rectangle(rect.x, rect.y - 1,
+ rect.width, rect.height))
+
+ # Get diagonal rects
+ if rect.x + rect.width < self.width - 1 and \
+ rect.y + rect.height < self.height - 1:
+ new_rects.append(gtk.gdk.Rectangle(rect.x + 1, rect.y + 1,
+ rect.width, rect.height))
+
+ if rect.x - 1 > 0 and rect.y + rect.height < self.height - 1:
+ new_rects.append(gtk.gdk.Rectangle(rect.x - 1, rect.y + 1,
+ rect.width, rect.height))
+
+ if rect.x + rect.width < self.width - 1 and rect.y - 1 > 0:
+ new_rects.append(gtk.gdk.Rectangle(rect.x + 1, rect.y - 1,
+ rect.width, rect.height))
+
+ if rect.x - 1 > 0 and rect.y - 1 > 0:
+ new_rects.append(gtk.gdk.Rectangle(rect.x - 1, rect.y - 1,
+ rect.width, rect.height))
+
+ random.shuffle(new_rects)
+
+ best_rect = None
+ for new_rect in new_rects:
+ new_weight = self.compute_weight(new_rect)
+ if new_weight < weight:
+ best_rect = new_rect
+ weight = new_weight
+
+ if best_rect:
+ self._child_rects[child] = best_rect
+ weight = self._shift_child(child, weight)
+
+ return weight
+
+ def __solve_collisions_cb(self):
+ for i_ in range(_MAX_COLLISIONS_PER_REFRESH):
+ collision = self._collisions.pop(0)
+
+ old_rect = self._child_rects[collision]
+ self.remove_weight(old_rect)
+ weight = self.compute_weight(old_rect)
+ weight = self._shift_child(collision, weight)
+ self.add_weight(self._child_rects[collision])
+
+ # TODO: we shouldn't give up the first time we failed to find a
+ # better position.
+ if old_rect != self._child_rects[collision]:
+ self._detect_collisions(collision)
+ self.emit('child-changed', collision)
+ if weight > 0:
+ self._collisions.append(collision)
+
+ if not self._collisions:
+ self._collisions_sid = 0
+ return False
+
+ return True
+
+ def _detect_collisions(self, child):
+ collision_found = False
+ child_rect = self._child_rects[child]
+ for c in self._children:
+ intersection = child_rect.intersect(self._child_rects[c])
+ if c != child and intersection.width > 0:
+ if c not in self._locked_children and c not in self._collisions:
+ collision_found = True
+ self._collisions.append(c)
+
+ if collision_found:
+ if child not in self._collisions:
+ self._collisions.append(child)
+
+ if self._collisions and not self._collisions_sid:
+ self._collisions_sid = gobject.timeout_add(_REFRESH_RATE,
+ self.__solve_collisions_cb, priority=gobject.PRIORITY_LOW)
+
+ def get_child_rect(self, child):
+ return self._child_rects[child]
diff --git a/shell/src/jarabe/desktop/groupbox.py b/shell/src/jarabe/desktop/groupbox.py
new file mode 100644
index 0000000..89043fe
--- /dev/null
+++ b/shell/src/jarabe/desktop/groupbox.py
@@ -0,0 +1,92 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import gobject
+import hippo
+import gconf
+
+from sugar.graphics import style
+from sugar.graphics.icon import CanvasIcon
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.view.buddymenu import BuddyMenu
+from jarabe.model.buddy import get_owner_instance
+from jarabe.model import friends
+from jarabe.desktop.friendview import FriendView
+from jarabe.desktop.spreadlayout import SpreadLayout
+
+class GroupBox(hippo.Canvas):
+ __gtype_name__ = 'SugarGroupBox'
+ def __init__(self):
+ logging.debug("STARTUP: Loading the group view")
+
+ gobject.GObject.__init__(self)
+
+ self._box = hippo.CanvasBox()
+ self._box.props.background_color = style.COLOR_WHITE.get_int()
+ self.set_root(self._box)
+
+ self._friends = {}
+
+ self._layout = SpreadLayout()
+ self._box.set_layout(self._layout)
+
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string("/desktop/sugar/user/color"))
+
+ self._owner_icon = CanvasIcon(icon_name='computer-xo', cache=True,
+ xo_color=color)
+ self._owner_icon.props.size = style.LARGE_ICON_SIZE
+
+ self._owner_icon.set_palette(BuddyMenu(get_owner_instance()))
+ self._layout.add(self._owner_icon)
+
+ friends_model = friends.get_model()
+
+ for friend in friends_model:
+ self.add_friend(friend)
+
+ friends_model.connect('friend-added', self._friend_added_cb)
+ friends_model.connect('friend-removed', self._friend_removed_cb)
+
+ def add_friend(self, buddy_info):
+ icon = FriendView(buddy_info)
+ self._layout.add(icon)
+
+ self._friends[buddy_info.get_key()] = icon
+
+ def _friend_added_cb(self, data_model, buddy_info):
+ self.add_friend(buddy_info)
+
+ def _friend_removed_cb(self, data_model, key):
+ icon = self._friends[key]
+ self._layout.remove(icon)
+ del self._friends[key]
+ icon.destroy()
+
+ def do_size_allocate(self, allocation):
+ width = allocation.width
+ height = allocation.height
+
+ min_w_, icon_width = self._owner_icon.get_width_request()
+ min_h_, icon_height = self._owner_icon.get_height_request(icon_width)
+ x = (width - icon_width) / 2
+ y = (height - icon_height) / 2
+ self._layout.move(self._owner_icon, x, y)
+
+ hippo.Canvas.do_size_allocate(self, allocation)
diff --git a/shell/src/jarabe/desktop/homebox.py b/shell/src/jarabe/desktop/homebox.py
new file mode 100644
index 0000000..85279ff
--- /dev/null
+++ b/shell/src/jarabe/desktop/homebox.py
@@ -0,0 +1,298 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+import os
+
+import gobject
+import gtk
+
+from sugar.graphics import style
+from sugar.graphics import iconentry
+from sugar.graphics.radiotoolbutton import RadioToolButton
+from sugar.graphics.alert import Alert
+from sugar.graphics.icon import Icon
+
+from jarabe.desktop import favoritesview
+from jarabe.desktop.activitieslist import ActivitiesList
+
+_FAVORITES_VIEW = 0
+_LIST_VIEW = 1
+
+_AUTOSEARCH_TIMEOUT = 1000
+
+class HomeBox(gtk.VBox):
+ __gtype_name__ = 'SugarHomeBox'
+
+ def __init__(self):
+ logging.debug("STARTUP: Loading the home view")
+
+ gobject.GObject.__init__(self)
+
+ self._favorites_view = favoritesview.FavoritesView()
+ self._list_view = ActivitiesList()
+
+ self._toolbar = HomeToolbar()
+ self._toolbar.connect('query-changed', self.__toolbar_query_changed_cb)
+ self._toolbar.connect('view-changed', self.__toolbar_view_changed_cb)
+ self.pack_start(self._toolbar, expand=False)
+ self._toolbar.show()
+
+ self._set_view(_FAVORITES_VIEW)
+
+ def show_software_updates_alert(self):
+ alert = Alert()
+ updater_icon = Icon(icon_name='module-updater',
+ pixel_size = style.STANDARD_ICON_SIZE)
+ alert.props.icon = updater_icon
+ updater_icon.show()
+ alert.props.title = _('Software Update')
+ alert.props.msg = _('Update your activities to ensure'
+ ' compatibility with your new software')
+
+ cancel_icon = Icon(icon_name='dialog-cancel')
+ alert.add_button(gtk.RESPONSE_CANCEL, _('Cancel'), cancel_icon)
+
+ alert.add_button(gtk.RESPONSE_REJECT, _('Later'))
+
+ erase_icon = Icon(icon_name='dialog-ok')
+ alert.add_button(gtk.RESPONSE_OK, _('Check now'), erase_icon)
+
+ if self._list_view in self.get_children():
+ self._list_view.add_alert(alert)
+ else:
+ self._favorites_view.add_alert(alert)
+ alert.connect('response', self.__software_update_response_cb)
+
+ def __software_update_response_cb(self, alert, response_id):
+ if self._list_view in self.get_children():
+ self._list_view.remove_alert()
+ else:
+ self._favorites_view.remove_alert()
+
+ if response_id != gtk.RESPONSE_REJECT:
+ update_trigger_file = os.path.expanduser('~/.sugar-update')
+ try:
+ os.unlink(update_trigger_file)
+ except OSError:
+ logging.error('Software-update: Can not remove file %s',
+ update_trigger_file)
+
+ if response_id == gtk.RESPONSE_OK:
+ from jarabe.controlpanel.gui import ControlPanel
+ panel = ControlPanel()
+ panel.set_transient_for(self.get_toplevel())
+ panel.show()
+ panel.show_section_view('updater')
+ panel.set_section_view_auto_close()
+
+ def __toolbar_query_changed_cb(self, toolbar, query):
+ query = query.lower()
+ self._list_view.set_filter(query)
+
+ def __toolbar_view_changed_cb(self, toolbar, view):
+ self._set_view(view)
+
+ def _set_view(self, view):
+ if view == _FAVORITES_VIEW:
+ if self._list_view in self.get_children():
+ self.remove(self._list_view)
+
+ if self._favorites_view not in self.get_children():
+ self.add(self._favorites_view)
+ self._favorites_view.show()
+ elif view == _LIST_VIEW:
+ if self._favorites_view in self.get_children():
+ self.remove(self._favorites_view)
+
+ if self._list_view not in self.get_children():
+ self.add(self._list_view)
+ self._list_view.show()
+ else:
+ raise ValueError('Invalid view: %r' % view)
+
+ _REDRAW_TIMEOUT = 5 * 60 * 1000 # 5 minutes
+
+ def resume(self):
+ pass
+
+ def suspend(self):
+ pass
+
+ def has_activities(self):
+ # TODO: Do we need this?
+ #return self._donut.has_activities()
+ return False
+
+ def focus_search_entry(self):
+ self._toolbar.search_entry.grab_focus()
+
+ def set_resume_mode(self, resume_mode):
+ self._favorites_view.set_resume_mode(resume_mode)
+
+class HomeToolbar(gtk.Toolbar):
+ __gtype_name__ = 'SugarHomeToolbar'
+
+ __gsignals__ = {
+ 'query-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ 'view-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([object]))
+ }
+
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self._query = None
+ self._autosearch_timer = None
+
+ self._add_separator()
+
+ tool_item = gtk.ToolItem()
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ self.search_entry = iconentry.IconEntry()
+ self.search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY,
+ 'system-search')
+ self.search_entry.add_clear_button()
+ self.search_entry.set_width_chars(25)
+ self.search_entry.connect('activate', self.__entry_activated_cb)
+ self.search_entry.connect('changed', self.__entry_changed_cb)
+ tool_item.add(self.search_entry)
+ self.search_entry.set_sensitive(False)
+ self.search_entry.show()
+
+ self._add_separator(expand=True)
+
+ favorites_button = FavoritesButton()
+ favorites_button.connect('toggled', self.__view_button_toggled_cb,
+ _FAVORITES_VIEW)
+ self.insert(favorites_button, -1)
+ favorites_button.show()
+
+ self._list_button = RadioToolButton(named_icon='view-list')
+ self._list_button.props.group = favorites_button
+ self._list_button.props.tooltip = _('List view')
+ self._list_button.props.accelerator = _('<Ctrl>2')
+ self._list_button.connect('toggled', self.__view_button_toggled_cb,
+ _LIST_VIEW)
+ self.insert(self._list_button, -1)
+ self._list_button.show()
+
+ self._add_separator()
+
+ def __view_button_toggled_cb(self, button, view):
+ if button.props.active:
+ if view == _FAVORITES_VIEW:
+ self.search_entry.set_text('')
+ self.search_entry.set_sensitive(False)
+ self.emit('view-changed', view)
+ else:
+ self.search_entry.set_sensitive(True)
+ self.search_entry.grab_focus()
+ self.emit('view-changed', view)
+
+ def _add_separator(self, expand=False):
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ if expand:
+ separator.set_expand(True)
+ else:
+ separator.set_size_request(style.GRID_CELL_SIZE,
+ style.GRID_CELL_SIZE)
+ self.insert(separator, -1)
+ separator.show()
+
+ def __entry_activated_cb(self, entry):
+ if self._autosearch_timer:
+ gobject.source_remove(self._autosearch_timer)
+ new_query = entry.props.text
+ if self._query != new_query:
+ self._query = new_query
+
+ if self._query is not '':
+ self._list_button.props.active = True
+ self.emit('query-changed', self._query)
+
+ def __entry_changed_cb(self, entry):
+ if not entry.props.text:
+ entry.activate()
+ return
+
+ if self._autosearch_timer:
+ gobject.source_remove(self._autosearch_timer)
+ self._autosearch_timer = gobject.timeout_add(_AUTOSEARCH_TIMEOUT,
+ self.__autosearch_timer_cb)
+
+ def __autosearch_timer_cb(self):
+ self._autosearch_timer = None
+ self.search_entry.activate()
+ return False
+
+class FavoritesButton(RadioToolButton):
+ __gtype_name__ = 'SugarFavoritesButton'
+
+ def __init__(self):
+ RadioToolButton.__init__(self)
+
+ self.props.tooltip = _('Favorites view')
+ self.props.accelerator = _('<Ctrl>1')
+ self.props.group = None
+
+ favorites_settings = favoritesview.get_settings()
+ self._layout = favorites_settings.layout
+ self._update_icon()
+
+ # someday, this will be a gtk.Table()
+ layouts_grid = gtk.HBox()
+ layout_item = None
+ for layoutid, layoutclass in sorted(favoritesview.LAYOUT_MAP.items()):
+ layout_item = RadioToolButton(icon_name=layoutclass.icon_name,
+ group=layout_item, active=False)
+ if layoutid == self._layout:
+ layout_item.set_active(True)
+ layouts_grid.pack_start(layout_item, fill=False)
+ layout_item.connect('toggled', self.__layout_activate_cb,
+ layoutid)
+ layouts_grid.show_all()
+ self.props.palette.set_content(layouts_grid)
+
+ def __layout_activate_cb(self, menu_item, layout):
+ if not menu_item.get_active():
+ return
+ if self._layout == layout and self.props.active:
+ return
+
+ if self._layout != layout:
+ self._layout = layout
+ self._update_icon()
+
+ favorites_settings = favoritesview.get_settings()
+ favorites_settings.layout = layout
+
+ if not self.props.active:
+ self.props.active = True
+ else:
+ self.emit('toggled')
+
+ def _update_icon(self):
+ self.props.named_icon = favoritesview.LAYOUT_MAP[self._layout]\
+ .icon_name
+
diff --git a/shell/src/jarabe/desktop/homewindow.py b/shell/src/jarabe/desktop/homewindow.py
new file mode 100644
index 0000000..fec4289
--- /dev/null
+++ b/shell/src/jarabe/desktop/homewindow.py
@@ -0,0 +1,193 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import gtk
+
+from sugar.graphics import style
+from sugar.graphics import palettegroup
+
+from jarabe.desktop.meshbox import MeshBox
+from jarabe.desktop.homebox import HomeBox
+from jarabe.desktop.groupbox import GroupBox
+from jarabe.desktop.transitionbox import TransitionBox
+from jarabe.model.shell import ShellModel
+from jarabe.model import shell
+
+_HOME_PAGE = 0
+_GROUP_PAGE = 1
+_MESH_PAGE = 2
+_TRANSITION_PAGE = 3
+
+class HomeWindow(gtk.Window):
+ def __init__(self):
+ logging.debug('STARTUP: Loading the desktop window')
+ gtk.Window.__init__(self)
+
+ accel_group = gtk.AccelGroup()
+ self.set_data('sugar-accel-group', accel_group)
+ self.add_accel_group(accel_group)
+
+ self._active = False
+ self._fully_obscured = True
+
+ screen = self.get_screen()
+ screen.connect('size-changed', self.__screen_size_change_cb)
+ self.set_default_size(screen.get_width(),
+ screen.get_height())
+
+ self.realize()
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DESKTOP)
+
+ self.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
+ self.connect('visibility-notify-event',
+ self._visibility_notify_event_cb)
+ self.connect('map-event', self.__map_event_cb)
+ self.connect('key-press-event', self.__key_press_event_cb)
+ self.connect('key-release-event', self.__key_release_event_cb)
+
+ self._home_box = HomeBox()
+ self._group_box = GroupBox()
+ self._mesh_box = MeshBox()
+ self._transition_box = TransitionBox()
+
+ self.add(self._home_box)
+ self._home_box.show()
+
+ self._transition_box.connect('completed',
+ self._transition_completed_cb)
+
+ shell.get_model().zoom_level_changed.connect(
+ self.__zoom_level_changed_cb)
+
+ def _deactivate_view(self, level):
+ group = palettegroup.get_group("default")
+ group.popdown()
+ if level == ShellModel.ZOOM_HOME:
+ self._home_box.suspend()
+ elif level == ShellModel.ZOOM_MESH:
+ self._mesh_box.suspend()
+
+ def __screen_size_change_cb(self, screen):
+ self.resize(screen.get_width(), screen.get_height())
+
+ def _activate_view(self, level):
+ if level == ShellModel.ZOOM_HOME:
+ self._home_box.resume()
+ elif level == ShellModel.ZOOM_MESH:
+ self._mesh_box.resume()
+
+ def _visibility_notify_event_cb(self, window, event):
+ fully_obscured = (event.state == gtk.gdk.VISIBILITY_FULLY_OBSCURED)
+ if self._fully_obscured == fully_obscured:
+ return
+ self._fully_obscured = fully_obscured
+
+ if fully_obscured:
+ self._deactivate_view(shell.get_model().zoom_level)
+ else:
+ display = gtk.gdk.display_get_default()
+ screen_, x_, y_, modmask = display.get_pointer()
+ if modmask & gtk.gdk.MOD1_MASK:
+ self._home_box.set_resume_mode(False)
+ else:
+ self._home_box.set_resume_mode(True)
+
+ self._activate_view(shell.get_model().zoom_level)
+
+ def __key_press_event_cb(self, window, event):
+ if event.keyval in [gtk.keysyms.Alt_L, gtk.keysyms.Alt_R]:
+ self._home_box.set_resume_mode(False)
+ return False
+
+ def __key_release_event_cb(self, window, event):
+ if event.keyval in [gtk.keysyms.Alt_L, gtk.keysyms.Alt_R]:
+ self._home_box.set_resume_mode(True)
+ return False
+
+ def __map_event_cb(self, window, event):
+ # have to make the desktop window active
+ # since metacity doesn't make it on startup
+ timestamp = event.get_time()
+ if not timestamp:
+ timestamp = gtk.gdk.x11_get_server_time(self.window)
+ self.window.focus(timestamp)
+
+ def __zoom_level_changed_cb(self, **kwargs):
+ old_level = kwargs['old_level']
+ new_level = kwargs['new_level']
+
+ self._deactivate_view(old_level)
+ self._activate_view(new_level)
+
+ if old_level != ShellModel.ZOOM_ACTIVITY and \
+ new_level != ShellModel.ZOOM_ACTIVITY:
+ self.remove(self.get_child())
+ self.add(self._transition_box)
+ self._transition_box.show()
+
+ if new_level == ShellModel.ZOOM_HOME:
+ end_size = style.XLARGE_ICON_SIZE
+ elif new_level == ShellModel.ZOOM_GROUP:
+ end_size = style.LARGE_ICON_SIZE
+ elif new_level == ShellModel.ZOOM_MESH:
+ end_size = style.STANDARD_ICON_SIZE
+
+ if old_level == ShellModel.ZOOM_HOME:
+ start_size = style.XLARGE_ICON_SIZE
+ elif old_level == ShellModel.ZOOM_GROUP:
+ start_size = style.LARGE_ICON_SIZE
+ elif old_level == ShellModel.ZOOM_MESH:
+ start_size = style.STANDARD_ICON_SIZE
+
+ self._transition_box.start_transition(start_size, end_size)
+ else:
+ self._update_view(new_level)
+
+ def _transition_completed_cb(self, transition_box):
+ self._update_view(shell.get_model().zoom_level)
+
+ def _update_view(self, level):
+ if level == ShellModel.ZOOM_ACTIVITY:
+ return
+
+ current_child = self.get_child()
+ self.remove(current_child)
+
+ if level == ShellModel.ZOOM_HOME:
+ self.add(self._home_box)
+ self._home_box.show()
+ self._home_box.focus_search_entry()
+ elif level == ShellModel.ZOOM_GROUP:
+ self.add(self._group_box)
+ self._group_box.show()
+ elif level == ShellModel.ZOOM_MESH:
+ self.add(self._mesh_box)
+ self._mesh_box.show()
+ self._mesh_box.focus_search_entry()
+
+ def get_home_box(self):
+ return self._home_box
+
+_instance = None
+
+def get_instance():
+ global _instance
+ if not _instance:
+ _instance = HomeWindow()
+ return _instance
+
diff --git a/shell/src/jarabe/desktop/keydialog.py b/shell/src/jarabe/desktop/keydialog.py
new file mode 100644
index 0000000..1e6d17a
--- /dev/null
+++ b/shell/src/jarabe/desktop/keydialog.py
@@ -0,0 +1,317 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2009 One Laptop per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import hashlib
+from gettext import gettext as _
+
+import gtk
+import dbus
+
+from jarabe.model import network
+from jarabe.model.network import Secrets
+
+IW_AUTH_ALG_OPEN_SYSTEM = 'open'
+IW_AUTH_ALG_SHARED_KEY = 'shared'
+
+def string_is_hex(key):
+ is_hex = True
+ for c in key:
+ if not 'a' <= c.lower() <= 'f' and not '0' <= c <= '9':
+ is_hex = False
+ return is_hex
+
+def string_is_ascii(string):
+ try:
+ string.encode('ascii')
+ return True
+ except UnicodeEncodeError:
+ return False
+
+def string_to_hex(passphrase):
+ key = ''
+ for c in passphrase:
+ key += '%02x' % ord(c)
+ return key
+
+def hash_passphrase(passphrase):
+ # passphrase must have a length of 64
+ if len(passphrase) > 64:
+ passphrase = passphrase[:64]
+ elif len(passphrase) < 64:
+ while len(passphrase) < 64:
+ passphrase += passphrase[:64 - len(passphrase)]
+ passphrase = hashlib.md5(passphrase).digest()
+ return string_to_hex(passphrase)[:26]
+
+class CanceledKeyRequestError(dbus.DBusException):
+ def __init__(self):
+ dbus.DBusException.__init__(self)
+ self._dbus_error_name = network.NM_SETTINGS_IFACE + '.CanceledError'
+
+class KeyDialog(gtk.Dialog):
+ def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, settings,
+ response):
+ gtk.Dialog.__init__(self, flags=gtk.DIALOG_MODAL)
+ self.set_title("Wireless Key Required")
+
+ self._settings = settings
+ self._response = response
+ self._entry = None
+ self._ssid = ssid
+ self._flags = flags
+ self._wpa_flags = wpa_flags
+ self._rsn_flags = rsn_flags
+ self._dev_caps = dev_caps
+
+ self.set_has_separator(False)
+
+ label = gtk.Label("A wireless encryption key is required for\n" \
+ " the wireless network '%s'." % self._ssid)
+ self.vbox.pack_start(label)
+
+ self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OK, gtk.RESPONSE_OK)
+ self.set_default_response(gtk.RESPONSE_OK)
+ self.set_has_separator(True)
+
+ def add_key_entry(self):
+ self._entry = gtk.Entry()
+ self._entry.connect('changed', self._update_response_sensitivity)
+ self._entry.connect('activate', self._entry_activate_cb)
+ self.vbox.pack_start(self._entry)
+ self.vbox.set_spacing(6)
+ self.vbox.show_all()
+
+ self._update_response_sensitivity()
+ self._entry.grab_focus()
+
+ def _entry_activate_cb(self, entry):
+ self.response(gtk.RESPONSE_OK)
+
+ def create_security(self):
+ raise NotImplementedError
+
+ def get_response_object(self):
+ return self._response
+
+WEP_PASSPHRASE = 1
+WEP_HEX = 2
+WEP_ASCII = 3
+
+class WEPKeyDialog(KeyDialog):
+ def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, settings,
+ response):
+ KeyDialog.__init__(self, ssid, flags, wpa_flags, rsn_flags,
+ dev_caps, settings, response)
+
+ # WEP key type
+ self.key_store = gtk.ListStore(str, int)
+ self.key_store.append(["Passphrase (128-bit)", WEP_PASSPHRASE])
+ self.key_store.append(["Hex (40/128-bit)", WEP_HEX])
+ self.key_store.append(["ASCII (40/128-bit)", WEP_ASCII])
+
+ self.key_combo = gtk.ComboBox(self.key_store)
+ cell = gtk.CellRendererText()
+ self.key_combo.pack_start(cell, True)
+ self.key_combo.add_attribute(cell, 'text', 0)
+ self.key_combo.set_active(0)
+ self.key_combo.connect('changed', self._key_combo_changed_cb)
+
+ hbox = gtk.HBox()
+ hbox.pack_start(gtk.Label(_("Key Type:")))
+ hbox.pack_start(self.key_combo)
+ hbox.show_all()
+ self.vbox.pack_start(hbox)
+
+ # Key entry field
+ self.add_key_entry()
+
+ # WEP authentication mode
+ self.auth_store = gtk.ListStore(str, str)
+ self.auth_store.append(["Open System", IW_AUTH_ALG_OPEN_SYSTEM])
+ self.auth_store.append(["Shared Key", IW_AUTH_ALG_SHARED_KEY])
+
+ self.auth_combo = gtk.ComboBox(self.auth_store)
+ cell = gtk.CellRendererText()
+ self.auth_combo.pack_start(cell, True)
+ self.auth_combo.add_attribute(cell, 'text', 0)
+ self.auth_combo.set_active(0)
+
+ hbox = gtk.HBox()
+ hbox.pack_start(gtk.Label(_("Authentication Type:")))
+ hbox.pack_start(self.auth_combo)
+ hbox.show_all()
+
+ self.vbox.pack_start(hbox)
+
+ def _key_combo_changed_cb(self, widget):
+ self._update_response_sensitivity()
+
+ def _get_security(self):
+ key = self._entry.get_text()
+
+ it = self.key_combo.get_active_iter()
+ (key_type, ) = self.key_store.get(it, 1)
+
+ if key_type == WEP_PASSPHRASE:
+ key = hash_passphrase(key)
+ elif key_type == WEP_ASCII:
+ key = string_to_hex(key)
+
+ it = self.auth_combo.get_active_iter()
+ (auth_alg, ) = self.auth_store.get(it, 1)
+
+ return (key, auth_alg)
+
+ def print_security(self):
+ (key, auth_alg) = self._get_security()
+ print "Key: %s" % key
+ print "Auth: %d" % auth_alg
+
+ def create_security(self):
+ (key, auth_alg) = self._get_security()
+ secrets = Secrets(self._settings)
+ secrets.wep_key = key
+ secrets.auth_alg = auth_alg
+ return secrets
+
+ def _update_response_sensitivity(self, ignored=None):
+ key = self._entry.get_text()
+ it = self.key_combo.get_active_iter()
+ (key_type, ) = self.key_store.get(it, 1)
+
+ valid = False
+ if key_type == WEP_PASSPHRASE:
+ # As the md5 passphrase can be of any length and has no indicator,
+ # we cannot check for the validity of the input.
+ if len(key) > 0:
+ valid = True
+ elif key_type == WEP_ASCII:
+ if len(key) == 5 or len(key) == 13:
+ valid = string_is_ascii(key)
+ elif key_type == WEP_HEX:
+ if len(key) == 10 or len(key) == 26:
+ valid = string_is_hex(key)
+
+ self.set_response_sensitive(gtk.RESPONSE_OK, valid)
+
+class WPAKeyDialog(KeyDialog):
+ def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, settings,
+ response):
+ KeyDialog.__init__(self, ssid, flags, wpa_flags, rsn_flags,
+ dev_caps, settings, response)
+ self.add_key_entry()
+
+ self.store = gtk.ListStore(str)
+ self.store.append([_("WPA & WPA2 Personal")])
+
+ self.combo = gtk.ComboBox(self.store)
+ cell = gtk.CellRendererText()
+ self.combo.pack_start(cell, True)
+ self.combo.add_attribute(cell, 'text', 0)
+ self.combo.set_active(0)
+
+ self.hbox = gtk.HBox()
+ self.hbox.pack_start(gtk.Label(_("Wireless Security:")))
+ self.hbox.pack_start(self.combo)
+ self.hbox.show_all()
+
+ self.vbox.pack_start(self.hbox)
+
+ def _get_security(self):
+ ssid = self._ssid
+ key = self._entry.get_text()
+ is_hex = string_is_hex(key)
+
+ real_key = None
+ if len(key) == 64 and is_hex:
+ # Hex key
+ real_key = key
+ elif len(key) >= 8 and len(key) <= 63:
+ # passphrase
+ from subprocess import Popen, PIPE
+ p = Popen(['wpa_passphrase', ssid, key], stdout=PIPE)
+ for line in p.stdout:
+ if line.strip().startswith("psk="):
+ real_key = line.strip()[4:]
+ if p.wait() != 0:
+ raise RuntimeError("Error hashing passphrase")
+ if real_key and len(real_key) != 64:
+ real_key = None
+
+ if not real_key:
+ raise RuntimeError("Invalid key")
+
+ return real_key
+
+ def print_security(self):
+ key = self._get_security()
+ print "Key: %s" % key
+
+ def create_security(self):
+ secrets = Secrets(self._settings)
+ secrets.psk = self._get_security()
+ return secrets
+
+ def _update_response_sensitivity(self, ignored=None):
+ key = self._entry.get_text()
+ is_hex = string_is_hex(key)
+
+ valid = False
+ if len(key) == 64 and is_hex:
+ # hex key
+ valid = True
+ elif len(key) >= 8 and len(key) <= 63:
+ # passphrase
+ valid = True
+ self.set_response_sensitive(gtk.RESPONSE_OK, valid)
+ return False
+
+def create(ssid, flags, wpa_flags, rsn_flags, dev_caps, settings, response):
+ if wpa_flags == network.NM_802_11_AP_SEC_NONE and \
+ rsn_flags == network.NM_802_11_AP_SEC_NONE:
+ key_dialog = WEPKeyDialog(ssid, flags, wpa_flags, rsn_flags,
+ dev_caps, settings, response)
+ else:
+ key_dialog = WPAKeyDialog(ssid, flags, wpa_flags, rsn_flags,
+ dev_caps, settings, response)
+
+ key_dialog.connect("response", _key_dialog_response_cb)
+ key_dialog.connect("destroy", _key_dialog_destroy_cb)
+ key_dialog.show_all()
+
+def _key_dialog_destroy_cb(key_dialog, data=None):
+ _key_dialog_response_cb(key_dialog, gtk.RESPONSE_CANCEL)
+
+def _key_dialog_response_cb(key_dialog, response_id):
+ response = key_dialog.get_response_object()
+ secrets = None
+ if response_id == gtk.RESPONSE_OK:
+ secrets = key_dialog.create_security()
+
+ if response_id in [gtk.RESPONSE_CANCEL, gtk.RESPONSE_NONE]:
+ # key dialog dialog was canceled; send the error back to NM
+ response.set_error(CanceledKeyRequestError())
+ elif response_id == gtk.RESPONSE_OK:
+ if not secrets:
+ raise RuntimeError("Invalid security arguments.")
+ response.set_secrets(secrets)
+ else:
+ raise RuntimeError("Unhandled key dialog response %d" % response_id)
+
+ key_dialog.destroy()
+
diff --git a/shell/src/jarabe/desktop/meshbox.py b/shell/src/jarabe/desktop/meshbox.py
new file mode 100644
index 0000000..cf72053
--- /dev/null
+++ b/shell/src/jarabe/desktop/meshbox.py
@@ -0,0 +1,670 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+# Copyright (C) 2009-2010 One Laptop per Child
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+
+import dbus
+import hippo
+import glib
+import gobject
+import gtk
+import gconf
+
+from sugar.graphics.icon import CanvasIcon, Icon
+from sugar.graphics import style
+from sugar.graphics import palette
+from sugar.graphics import iconentry
+from sugar.graphics.menuitem import MenuItem
+
+from jarabe.model import neighborhood
+from jarabe.model.buddy import get_owner_instance
+from jarabe.view.buddyicon import BuddyIcon
+from jarabe.desktop.snowflakelayout import SnowflakeLayout
+from jarabe.desktop.spreadlayout import SpreadLayout
+from jarabe.desktop.networkviews import WirelessNetworkView
+from jarabe.desktop.networkviews import OlpcMeshView
+from jarabe.desktop.networkviews import SugarAdhocView
+from jarabe.model import network
+from jarabe.model.network import AccessPoint
+from jarabe.model.olpcmesh import OlpcMeshManager
+from jarabe.model.adhoc import get_adhoc_manager_instance
+from jarabe.journal import misc
+
+_NM_SERVICE = 'org.freedesktop.NetworkManager'
+_NM_IFACE = 'org.freedesktop.NetworkManager'
+_NM_PATH = '/org/freedesktop/NetworkManager'
+_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
+_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
+_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
+_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
+_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
+
+_AP_ICON_NAME = 'network-wireless'
+_OLPC_MESH_ICON_NAME = 'network-mesh'
+
+class ActivityView(hippo.CanvasBox):
+ def __init__(self, model):
+ hippo.CanvasBox.__init__(self)
+
+ self._model = model
+ self._model.connect('current-buddy-added', self.__buddy_added_cb)
+ self._model.connect('current-buddy-removed', self.__buddy_removed_cb)
+
+ self._icons = {}
+ self._palette = None
+
+ self._layout = SnowflakeLayout()
+ self.set_layout(self._layout)
+
+ self._icon = self._create_icon()
+ self._layout.add(self._icon, center=True)
+
+ self._palette = self._create_palette()
+ self._icon.set_palette(self._palette)
+
+ for buddy in self._model.props.current_buddies:
+ self._add_buddy(buddy)
+
+ def _create_icon(self):
+ icon = CanvasIcon(file_name=self._model.bundle.get_icon(),
+ xo_color=self._model.get_color(), cache=True,
+ size=style.STANDARD_ICON_SIZE)
+ icon.connect('activated', self._clicked_cb)
+ return icon
+
+ def _create_palette(self):
+ p_text = glib.markup_escape_text(self._model.bundle.get_name())
+ p_icon = Icon(file=self._model.bundle.get_icon(),
+ xo_color=self._model.get_color())
+ p_icon.props.icon_size = gtk.ICON_SIZE_LARGE_TOOLBAR
+ p = palette.Palette(None,
+ primary_text=p_text,
+ icon=p_icon)
+
+ private = self._model.props.private
+ joined = get_owner_instance() in self._model.props.buddies
+
+ if joined:
+ item = MenuItem(_('Resume'), 'activity-start')
+ item.connect('activate', self._clicked_cb)
+ item.show()
+ p.menu.append(item)
+ elif not private:
+ item = MenuItem(_('Join'), 'activity-start')
+ item.connect('activate', self._clicked_cb)
+ item.show()
+ p.menu.append(item)
+
+ return p
+
+ def has_buddy_icon(self, key):
+ return self._icons.has_key(key)
+
+ def __buddy_added_cb(self, activity, buddy):
+ self._add_buddy(buddy)
+
+ def _add_buddy(self, buddy):
+ icon = BuddyIcon(buddy, style.STANDARD_ICON_SIZE)
+ self._icons[buddy.props.key] = icon
+ self._layout.add(icon)
+
+ def __buddy_removed_cb(self, activity, buddy):
+ icon = self._icons[buddy.props.key]
+ del self._icons[buddy.props.key]
+ icon.destroy()
+
+ def _clicked_cb(self, item):
+ bundle = self._model.get_bundle()
+ misc.launch(bundle, activity_id=self._model.activity_id,
+ color=self._model.get_color())
+
+ def set_filter(self, query):
+ text_to_check = self._model.bundle.get_name().lower() + \
+ self._model.bundle.get_bundle_id().lower()
+ if text_to_check.find(query) == -1:
+ self._icon.props.stroke_color = '#D5D5D5'
+ self._icon.props.fill_color = style.COLOR_TRANSPARENT.get_svg()
+ else:
+ self._icon.props.xo_color = self._model.get_color()
+
+ for icon in self._icons.itervalues():
+ if hasattr(icon, 'set_filter'):
+ icon.set_filter(query)
+
+_AUTOSEARCH_TIMEOUT = 1000
+
+
+class MeshToolbar(gtk.Toolbar):
+ __gtype_name__ = 'MeshToolbar'
+
+ __gsignals__ = {
+ 'query-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str]))
+ }
+
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self._query = None
+ self._autosearch_timer = None
+
+ self._add_separator()
+
+ tool_item = gtk.ToolItem()
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ self.search_entry = iconentry.IconEntry()
+ self.search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY,
+ 'system-search')
+ self.search_entry.add_clear_button()
+ self.search_entry.set_width_chars(25)
+ self.search_entry.connect('activate', self._entry_activated_cb)
+ self.search_entry.connect('changed', self._entry_changed_cb)
+ tool_item.add(self.search_entry)
+ self.search_entry.show()
+
+ self._add_separator(expand=True)
+
+ def _add_separator(self, expand=False):
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ if expand:
+ separator.set_expand(True)
+ else:
+ separator.set_size_request(style.GRID_CELL_SIZE,
+ style.GRID_CELL_SIZE)
+ self.insert(separator, -1)
+ separator.show()
+
+ def _entry_activated_cb(self, entry):
+ if self._autosearch_timer:
+ gobject.source_remove(self._autosearch_timer)
+ new_query = entry.props.text
+ if self._query != new_query:
+ self._query = new_query
+ self.emit('query-changed', self._query)
+
+ def _entry_changed_cb(self, entry):
+ if not entry.props.text:
+ entry.activate()
+ return
+
+ if self._autosearch_timer:
+ gobject.source_remove(self._autosearch_timer)
+ self._autosearch_timer = gobject.timeout_add(_AUTOSEARCH_TIMEOUT,
+ self._autosearch_timer_cb)
+
+ def _autosearch_timer_cb(self):
+ logging.debug('_autosearch_timer_cb')
+ self._autosearch_timer = None
+ self.search_entry.activate()
+ return False
+
+
+class DeviceObserver(gobject.GObject):
+ __gsignals__ = {
+ 'access-point-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'access-point-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+ def __init__(self, device):
+ gobject.GObject.__init__(self)
+ self._bus = dbus.SystemBus()
+ self.device = device
+
+ wireless = dbus.Interface(device, _NM_WIRELESS_IFACE)
+ wireless.GetAccessPoints(reply_handler=self._get_access_points_reply_cb,
+ error_handler=self._get_access_points_error_cb)
+
+ self._bus.add_signal_receiver(self.__access_point_added_cb,
+ signal_name='AccessPointAdded',
+ path=device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+ self._bus.add_signal_receiver(self.__access_point_removed_cb,
+ signal_name='AccessPointRemoved',
+ path=device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
+ def _get_access_points_reply_cb(self, access_points_o):
+ for ap_o in access_points_o:
+ ap = self._bus.get_object(_NM_SERVICE, ap_o)
+ self.emit('access-point-added', ap)
+
+ def _get_access_points_error_cb(self, err):
+ logging.error('Failed to get access points: %s', err)
+
+ def __access_point_added_cb(self, access_point_o):
+ ap = self._bus.get_object(_NM_SERVICE, access_point_o)
+ self.emit('access-point-added', ap)
+
+ def __access_point_removed_cb(self, access_point_o):
+ self.emit('access-point-removed', access_point_o)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__access_point_added_cb,
+ signal_name='AccessPointAdded',
+ path=self.device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+ self._bus.remove_signal_receiver(self.__access_point_removed_cb,
+ signal_name='AccessPointRemoved',
+ path=self.device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
+
+class NetworkManagerObserver(object):
+
+ _SHOW_ADHOC_GCONF_KEY = '/desktop/sugar/network/adhoc'
+
+ def __init__(self, box):
+ self._box = box
+ self._bus = None
+ self._devices = {}
+ self._netmgr = None
+ self._olpc_mesh_device_o = None
+
+ client = gconf.client_get_default()
+ self._have_adhoc_networks = client.get_bool(self._SHOW_ADHOC_GCONF_KEY)
+
+ def listen(self):
+ try:
+ self._bus = dbus.SystemBus()
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ self._netmgr = dbus.Interface(obj, _NM_IFACE)
+ except dbus.DBusException:
+ logging.debug('%s service not available', _NM_SERVICE)
+ return
+
+ self._netmgr.GetDevices(reply_handler=self.__get_devices_reply_cb,
+ error_handler=self.__get_devices_error_cb)
+
+ self._bus.add_signal_receiver(self.__device_added_cb,
+ signal_name='DeviceAdded',
+ dbus_interface=_NM_IFACE)
+ self._bus.add_signal_receiver(self.__device_removed_cb,
+ signal_name='DeviceRemoved',
+ dbus_interface=_NM_IFACE)
+ self._bus.add_signal_receiver(self.__properties_changed_cb,
+ signal_name='PropertiesChanged',
+ dbus_interface=_NM_IFACE)
+
+ settings = network.get_settings()
+ if settings is not None:
+ settings.secrets_request.connect(self.__secrets_request_cb)
+
+ def __secrets_request_cb(self, **kwargs):
+ # FIXME It would be better to do all of this async, but I cannot think
+ # of a good way to. NM could really use some love here.
+
+ netmgr_props = dbus.Interface(
+ self._netmgr, 'org.freedesktop.DBus.Properties')
+ active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
+
+ for conn_o in active_connections_o:
+ obj = self._bus.get_object(_NM_IFACE, conn_o)
+ props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
+ if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+ ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+ found = False
+ if ap_o != '/':
+ for net in self._box.wireless_networks.values():
+ if net.find_ap(ap_o) is not None:
+ found = True
+ settings = kwargs['connection'].get_settings()
+ net.create_keydialog(settings, kwargs['response'])
+ if not found:
+ logging.error('Could not determine AP for'
+ ' specific object %s' % conn_o)
+
+ def __get_devices_reply_cb(self, devices_o):
+ for dev_o in devices_o:
+ self._check_device(dev_o)
+
+ def __get_devices_error_cb(self, err):
+ logging.error('Failed to get devices: %s', err)
+
+ def _check_device(self, device_o):
+ device = self._bus.get_object(_NM_SERVICE, device_o)
+ props = dbus.Interface(device, 'org.freedesktop.DBus.Properties')
+
+ device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
+ if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
+ self._devices[device_o] = DeviceObserver(device)
+ self._devices[device_o].connect('access-point-added',
+ self.__ap_added_cb)
+ self._devices[device_o].connect('access-point-removed',
+ self.__ap_removed_cb)
+ if self._have_adhoc_networks:
+ self._box.add_adhoc_networks(device)
+ elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+ self._olpc_mesh_device_o = device_o
+ self._box.enable_olpc_mesh(device)
+
+ def _get_device_path_error_cb(self, err):
+ logging.error('Failed to get device type: %s', err)
+
+ def __device_added_cb(self, device_o):
+ self._check_device(device_o)
+
+ def __device_removed_cb(self, device_o):
+ if device_o in self._devices:
+ observer = self._devices[device_o]
+ observer.disconnect()
+ del self._devices[device_o]
+ if self._have_adhoc_networks:
+ self._box.remove_adhoc_networks()
+ return
+
+ if self._olpc_mesh_device_o == device_o:
+ self._box.disable_olpc_mesh(device_o)
+
+ def __ap_added_cb(self, device_observer, access_point):
+ self._box.add_access_point(device_observer.device, access_point)
+
+ def __ap_removed_cb(self, device_observer, access_point_o):
+ self._box.remove_access_point(access_point_o)
+
+ def __properties_changed_cb(self, properties):
+ if 'WirelessHardwareEnabled' in properties:
+ if properties['WirelessHardwareEnabled']:
+ if not self._have_adhoc_networks:
+ self._box.remove_adhoc_networks()
+ elif properties['WirelessHardwareEnabled']:
+ for device in self._devices:
+ if self._have_adhoc_networks:
+ self._box.add_adhoc_networks(device)
+
+
+class MeshBox(gtk.VBox):
+ __gtype_name__ = 'SugarMeshBox'
+
+ def __init__(self):
+ logging.debug("STARTUP: Loading the mesh view")
+
+ gobject.GObject.__init__(self)
+
+ self.wireless_networks = {}
+ self._adhoc_manager = None
+ self._adhoc_networks = []
+
+ self._model = neighborhood.get_model()
+ self._buddies = {}
+ self._activities = {}
+ self._mesh = []
+ self._buddy_to_activity = {}
+ self._suspended = True
+ self._query = ''
+ self._owner_icon = None
+
+ self._toolbar = MeshToolbar()
+ self._toolbar.connect('query-changed', self._toolbar_query_changed_cb)
+ self.pack_start(self._toolbar, expand=False)
+ self._toolbar.show()
+
+ canvas = hippo.Canvas()
+ self.add(canvas)
+ canvas.show()
+
+ self._layout_box = hippo.CanvasBox( \
+ background_color=style.COLOR_WHITE.get_int())
+ canvas.set_root(self._layout_box)
+
+ self._layout = SpreadLayout()
+ self._layout_box.set_layout(self._layout)
+
+ for buddy_model in self._model.get_buddies():
+ self._add_buddy(buddy_model)
+
+ self._model.connect('buddy-added', self._buddy_added_cb)
+ self._model.connect('buddy-removed', self._buddy_removed_cb)
+
+ for activity_model in self._model.get_activities():
+ self._add_activity(activity_model)
+
+ self._model.connect('activity-added', self._activity_added_cb)
+ self._model.connect('activity-removed', self._activity_removed_cb)
+
+ netmgr_observer = NetworkManagerObserver(self)
+ netmgr_observer.listen()
+
+ def do_size_allocate(self, allocation):
+ width = allocation.width
+ height = allocation.height
+
+ min_w_, icon_width = self._owner_icon.get_width_request()
+ min_h_, icon_height = self._owner_icon.get_height_request(icon_width)
+ x = (width - icon_width) / 2
+ y = (height - icon_height) / 2 - style.GRID_CELL_SIZE
+ self._layout.move(self._owner_icon, x, y)
+
+ gtk.VBox.do_size_allocate(self, allocation)
+
+ def _buddy_added_cb(self, model, buddy_model):
+ self._add_buddy(buddy_model)
+
+ def _buddy_removed_cb(self, model, buddy_model):
+ self._remove_buddy(buddy_model)
+
+ def _activity_added_cb(self, model, activity_model):
+ self._add_activity(activity_model)
+
+ def _activity_removed_cb(self, model, activity_model):
+ self._remove_activity(activity_model)
+
+ def _add_buddy(self, buddy_model):
+ logging.debug('MeshBox._add_buddy %r', buddy_model.props.key)
+ buddy_model.connect('notify::current-activity',
+ self.__buddy_notify_current_activity_cb)
+ if buddy_model.props.current_activity is not None:
+ return
+ icon = BuddyIcon(buddy_model)
+ if buddy_model.is_owner():
+ self._owner_icon = icon
+ self._layout.add(icon)
+
+ if hasattr(icon, 'set_filter'):
+ icon.set_filter(self._query)
+
+ self._buddies[buddy_model.props.key] = icon
+
+ def _remove_buddy(self, buddy_model):
+ logging.debug('MeshBox._remove_buddy')
+ icon = self._buddies[buddy_model.props.key]
+ self._layout.remove(icon)
+ del self._buddies[buddy_model.props.key]
+ icon.destroy()
+
+ def __buddy_notify_current_activity_cb(self, buddy_model, pspec):
+ logging.debug('MeshBox.__buddy_notify_current_activity_cb %s',
+ buddy_model.props.current_activity)
+ if buddy_model.props.current_activity is None:
+ if not buddy_model.props.key in self._buddies:
+ self._add_buddy(buddy_model)
+ elif buddy_model.props.key in self._buddies:
+ self._remove_buddy(buddy_model)
+
+ def _add_activity(self, activity_model):
+ icon = ActivityView(activity_model)
+ self._layout.add(icon)
+
+ if hasattr(icon, 'set_filter'):
+ icon.set_filter(self._query)
+
+ self._activities[activity_model.activity_id] = icon
+
+ def _remove_activity(self, activity_model):
+ icon = self._activities[activity_model.activity_id]
+ self._layout.remove(icon)
+ del self._activities[activity_model.activity_id]
+ icon.destroy()
+
+ # add AP to its corresponding network icon on the desktop,
+ # creating one if it doesn't already exist
+ def _add_ap_to_network(self, ap):
+ hash = ap.network_hash()
+ if hash in self.wireless_networks:
+ self.wireless_networks[hash].add_ap(ap)
+ else:
+ # this is a new network
+ icon = WirelessNetworkView(ap)
+ self.wireless_networks[hash] = icon
+ self._layout.add(icon)
+ if hasattr(icon, 'set_filter'):
+ icon.set_filter(self._query)
+
+ def _remove_net_if_empty(self, net, hash):
+ # remove a network if it has no APs left
+ if net.num_aps() == 0:
+ net.disconnect()
+ self._layout.remove(net)
+ del self.wireless_networks[hash]
+
+ def _ap_props_changed_cb(self, ap, old_hash):
+ # if we have mesh hardware, ignore OLPC mesh networks that appear as
+ # normal wifi networks
+ if len(self._mesh) > 0 and ap.mode == network.NM_802_11_MODE_ADHOC \
+ and ap.name == "olpc-mesh":
+ logging.debug("ignoring OLPC mesh IBSS")
+ ap.disconnect()
+ return
+
+ if self._adhoc_manager is not None and \
+ network.is_sugar_adhoc_network(ap.name) and \
+ ap.mode == network.NM_802_11_MODE_ADHOC:
+ if old_hash is None: # new Ad-hoc network finished initializing
+ self._adhoc_manager.add_access_point(ap)
+ # we are called as well in other cases but we do not need to
+ # act here as we don't display signal strength for Ad-hoc networks
+ return
+
+ if old_hash is None: # new AP finished initializing
+ self._add_ap_to_network(ap)
+ return
+
+ hash = ap.network_hash()
+ if old_hash == hash:
+ # no change in network identity, so just update signal strengths
+ self.wireless_networks[hash].update_strength()
+ return
+
+ # properties change includes a change of the identity of the network
+ # that it is on. so create this as a new network.
+ self.wireless_networks[old_hash].remove_ap(ap)
+ self._remove_net_if_empty(self.wireless_networks[old_hash], old_hash)
+ self._add_ap_to_network(ap)
+
+ def add_access_point(self, device, ap_o):
+ ap = AccessPoint(device, ap_o)
+ ap.connect('props-changed', self._ap_props_changed_cb)
+ ap.initialize()
+
+ def remove_access_point(self, ap_o):
+ if self._adhoc_manager is not None:
+ if self._adhoc_manager.is_sugar_adhoc_access_point(ap_o):
+ self._adhoc_manager.remove_access_point(ap_o)
+ return
+
+ # we don't keep an index of ap object path to network, but since
+ # we'll only ever have a handful of networks, just try them all...
+ for net in self.wireless_networks.values():
+ ap = net.find_ap(ap_o)
+ if not ap:
+ continue
+
+ ap.disconnect()
+ net.remove_ap(ap)
+ self._remove_net_if_empty(net, ap.network_hash())
+ return
+
+ # it's not an error if the AP isn't found, since we might have ignored
+ # it (e.g. olpc-mesh adhoc network)
+ logging.debug('Can not remove access point %s' % ap_o)
+
+ def add_adhoc_networks(self, device):
+ if self._adhoc_manager is None:
+ self._adhoc_manager = get_adhoc_manager_instance()
+ self._adhoc_manager.start_listening(device)
+ self._add_adhoc_network_icon(1)
+ self._add_adhoc_network_icon(6)
+ self._add_adhoc_network_icon(11)
+ self._adhoc_manager.autoconnect()
+
+ def remove_adhoc_networks(self):
+ for icon in self._adhoc_networks:
+ self._layout.remove(icon)
+ self._adhoc_networks = []
+
+ def _add_adhoc_network_icon(self, channel):
+ icon = SugarAdhocView(channel)
+ self._layout.add(icon)
+ self._adhoc_networks.append(icon)
+
+ def _add_olpc_mesh_icon(self, mesh_mgr, channel):
+ icon = OlpcMeshView(mesh_mgr, channel)
+ self._layout.add(icon)
+ self._mesh.append(icon)
+
+ def enable_olpc_mesh(self, mesh_device):
+ mesh_mgr = OlpcMeshManager(mesh_device)
+ self._add_olpc_mesh_icon(mesh_mgr, 1)
+ self._add_olpc_mesh_icon(mesh_mgr, 6)
+ self._add_olpc_mesh_icon(mesh_mgr, 11)
+
+ # the OLPC mesh can be recognised as a "normal" wifi network. remove
+ # any such normal networks if they have been created
+ for hash, net in self.wireless_networks.iteritems():
+ if not net.is_olpc_mesh():
+ continue
+
+ logging.debug("removing OLPC mesh IBSS")
+ net.remove_all_aps()
+ net.disconnect()
+ self._layout.remove(net)
+ del self.wireless_networks[hash]
+
+ def disable_olpc_mesh(self, mesh_device):
+ for icon in self._mesh:
+ icon.disconnect()
+ self._layout.remove(icon)
+ self._mesh = []
+
+ def suspend(self):
+ if not self._suspended:
+ self._suspended = True
+ for net in self.wireless_networks.values() + self._mesh:
+ net.props.paused = True
+
+ def resume(self):
+ if self._suspended:
+ self._suspended = False
+ for net in self.wireless_networks.values() + self._mesh:
+ net.props.paused = False
+
+ def _toolbar_query_changed_cb(self, toolbar, query):
+ self._query = query.lower()
+ for icon in self._layout_box.get_children():
+ if hasattr(icon, 'set_filter'):
+ icon.set_filter(self._query)
+
+ def focus_search_entry(self):
+ self._toolbar.search_entry.grab_focus()
diff --git a/shell/src/jarabe/desktop/networkviews.py b/shell/src/jarabe/desktop/networkviews.py
new file mode 100644
index 0000000..121c817
--- /dev/null
+++ b/shell/src/jarabe/desktop/networkviews.py
@@ -0,0 +1,716 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+# Copyright (C) 2009-2010 One Laptop per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+import hashlib
+
+import dbus
+import glib
+
+from sugar.graphics.icon import Icon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics import xocolor
+from sugar.graphics import style
+from sugar.graphics.icon import get_icon_state
+from sugar.graphics import palette
+from sugar.graphics.menuitem import MenuItem
+from sugar.util import unique_id
+from sugar import profile
+
+from jarabe.view.pulsingicon import CanvasPulsingIcon
+from jarabe.desktop import keydialog
+from jarabe.model import network
+from jarabe.model.network import Settings
+from jarabe.model.network import IP4Config
+from jarabe.model.network import WirelessSecurity
+from jarabe.model.adhoc import get_adhoc_manager_instance
+
+_NM_SERVICE = 'org.freedesktop.NetworkManager'
+_NM_IFACE = 'org.freedesktop.NetworkManager'
+_NM_PATH = '/org/freedesktop/NetworkManager'
+_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
+_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
+_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
+_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
+_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
+
+_AP_ICON_NAME = 'network-wireless'
+_OLPC_MESH_ICON_NAME = 'network-mesh'
+
+
+class WirelessNetworkView(CanvasPulsingIcon):
+ def __init__(self, initial_ap):
+ CanvasPulsingIcon.__init__(self, size=style.STANDARD_ICON_SIZE,
+ cache=True)
+ self._bus = dbus.SystemBus()
+ self._access_points = {initial_ap.model.object_path: initial_ap}
+ self._active_ap = None
+ self._device = initial_ap.device
+ self._palette_icon = None
+ self._disconnect_item = None
+ self._connect_item = None
+ self._greyed_out = False
+ self._name = initial_ap.name
+ self._mode = initial_ap.mode
+ self._strength = initial_ap.strength
+ self._flags = initial_ap.flags
+ self._wpa_flags = initial_ap.wpa_flags
+ self._rsn_flags = initial_ap.rsn_flags
+ self._device_caps = 0
+ self._device_state = None
+ self._connection = None
+ self._color = None
+
+ if self._mode == network.NM_802_11_MODE_ADHOC and \
+ network.is_sugar_adhoc_network(self._name):
+ self._color = profile.get_color()
+ else:
+ sha_hash = hashlib.sha1()
+ data = self._name + hex(self._flags)
+ sha_hash.update(data)
+ digest = hash(sha_hash.digest())
+ index = digest % len(xocolor.colors)
+
+ self._color = xocolor.XoColor('%s,%s' %
+ (xocolor.colors[index][0],
+ xocolor.colors[index][1]))
+
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self.props.pulse_color = pulse_color
+
+ self._palette = self._create_palette()
+ self.set_palette(self._palette)
+ self._palette_icon.props.xo_color = self._color
+
+ if self._mode != network.NM_802_11_MODE_ADHOC:
+ if network.find_connection_by_ssid(self._name) is not None:
+ self.props.badge_name = "emblem-favorite"
+ self._palette_icon.props.badge_name = "emblem-favorite"
+ elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
+ self.props.badge_name = "emblem-locked"
+ self._palette_icon.props.badge_name = "emblem-locked"
+ else:
+ self.props.badge_name = None
+ self._palette_icon.props.badge_name = None
+ else:
+ self.props.badge_name = None
+ self._palette_icon.props.badge_name = None
+
+ interface_props = dbus.Interface(self._device,
+ 'org.freedesktop.DBus.Properties')
+ interface_props.Get(_NM_DEVICE_IFACE, 'State',
+ reply_handler=self.__get_device_state_reply_cb,
+ error_handler=self.__get_device_state_error_cb)
+ interface_props.Get(_NM_WIRELESS_IFACE, 'WirelessCapabilities',
+ reply_handler=self.__get_device_caps_reply_cb,
+ error_handler=self.__get_device_caps_error_cb)
+ interface_props.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
+ reply_handler=self.__get_active_ap_reply_cb,
+ error_handler=self.__get_active_ap_error_cb)
+
+ self._bus.add_signal_receiver(self.__device_state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+ self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
+ def _create_palette(self):
+ icon_name = get_icon_state(_AP_ICON_NAME, self._strength)
+ self._palette_icon = Icon(icon_name=icon_name,
+ icon_size=style.STANDARD_ICON_SIZE,
+ badge_name=self.props.badge_name)
+
+ p = palette.Palette(primary_text=glib.markup_escape_text(self._name),
+ icon=self._palette_icon)
+
+ self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
+ self._connect_item.connect('activate', self.__connect_activate_cb)
+ p.menu.append(self._connect_item)
+
+ self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject')
+ self._disconnect_item.connect('activate',
+ self._disconnect_activate_cb)
+ p.menu.append(self._disconnect_item)
+
+ return p
+
+ def __device_state_changed_cb(self, new_state, old_state, reason):
+ self._device_state = new_state
+ self._update_state()
+
+ def __update_active_ap(self, ap_path):
+ if ap_path in self._access_points:
+ # save reference to active AP, so that we always display the
+ # strength of that one
+ self._active_ap = self._access_points[ap_path]
+ self.update_strength()
+ self._update_state()
+ elif self._active_ap is not None:
+ # revert to showing state of strongest AP again
+ self._active_ap = None
+ self.update_strength()
+ self._update_state()
+
+ def __wireless_properties_changed_cb(self, properties):
+ if 'ActiveAccessPoint' in properties:
+ self.__update_active_ap(properties['ActiveAccessPoint'])
+
+ def __get_active_ap_reply_cb(self, ap_path):
+ self.__update_active_ap(ap_path)
+
+ def __get_active_ap_error_cb(self, err):
+ logging.error('Error getting the active access point: %s', err)
+
+ def __get_device_caps_reply_cb(self, caps):
+ self._device_caps = caps
+
+ def __get_device_caps_error_cb(self, err):
+ logging.error('Error getting the wireless device properties: %s', err)
+
+ def __get_device_state_reply_cb(self, state):
+ self._device_state = state
+ self._update()
+
+ def __get_device_state_error_cb(self, err):
+ logging.error('Error getting the device state: %s', err)
+
+ def _update(self):
+ self._update_state()
+ self._update_color()
+
+ def _update_state(self):
+ if self._active_ap is not None:
+ state = self._device_state
+ else:
+ state = network.DEVICE_STATE_UNKNOWN
+
+ if self._mode == network.NM_802_11_MODE_ADHOC and \
+ network.is_sugar_adhoc_network(self._name):
+ channel = max([1] + [ap.channel for ap in
+ self._access_points.values()])
+ if state == network.DEVICE_STATE_ACTIVATED:
+ icon_name = 'network-adhoc-%s-connected' % channel
+ else:
+ icon_name = 'network-adhoc-%s' % channel
+ self.props.icon_name = icon_name
+ icon = self._palette.props.icon
+ icon.props.icon_name = icon_name
+ else:
+ if state == network.DEVICE_STATE_ACTIVATED:
+ connection = network.find_connection_by_ssid(self._name)
+ if connection is not None:
+ if self._mode == network.NM_802_11_MODE_INFRA:
+ connection.set_connected()
+ icon_name = '%s-connected' % _AP_ICON_NAME
+ else:
+ icon_name = _AP_ICON_NAME
+
+ icon_name = get_icon_state(icon_name, self._strength)
+ if icon_name:
+ self.props.icon_name = icon_name
+ icon = self._palette.props.icon
+ icon.props.icon_name = icon_name
+
+ if state == network.DEVICE_STATE_PREPARE or \
+ state == network.DEVICE_STATE_CONFIG or \
+ state == network.DEVICE_STATE_NEED_AUTH or \
+ state == network.DEVICE_STATE_IP_CONFIG:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connecting...')
+ self.props.pulsing = True
+ elif state == network.DEVICE_STATE_ACTIVATED:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connected')
+ self.props.pulsing = False
+ else:
+ if self._disconnect_item:
+ self._disconnect_item.hide()
+ self._connect_item.show()
+ self._palette.props.secondary_text = None
+ self.props.pulsing = False
+
+ def _update_color(self):
+ if self._greyed_out:
+ self.props.pulsing = False
+ self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
+ else:
+ self.props.base_color = self._color
+
+ def _disconnect_activate_cb(self, item):
+ pass
+
+ def _add_ciphers_from_flags(self, flags, pairwise):
+ ciphers = []
+ if pairwise:
+ if flags & network.NM_802_11_AP_SEC_PAIR_TKIP:
+ ciphers.append("tkip")
+ if flags & network.NM_802_11_AP_SEC_PAIR_CCMP:
+ ciphers.append("ccmp")
+ else:
+ if flags & network.NM_802_11_AP_SEC_GROUP_WEP40:
+ ciphers.append("wep40")
+ if flags & network.NM_802_11_AP_SEC_GROUP_WEP104:
+ ciphers.append("wep104")
+ if flags & network.NM_802_11_AP_SEC_GROUP_TKIP:
+ ciphers.append("tkip")
+ if flags & network.NM_802_11_AP_SEC_GROUP_CCMP:
+ ciphers.append("ccmp")
+ return ciphers
+
+ def _get_security(self):
+ if not (self._flags & network.NM_802_11_AP_FLAGS_PRIVACY) and \
+ (self._wpa_flags == network.NM_802_11_AP_SEC_NONE) and \
+ (self._rsn_flags == network.NM_802_11_AP_SEC_NONE):
+ # No security
+ return None
+
+ if (self._flags & network.NM_802_11_AP_FLAGS_PRIVACY) and \
+ (self._wpa_flags == network.NM_802_11_AP_SEC_NONE) and \
+ (self._rsn_flags == network.NM_802_11_AP_SEC_NONE):
+ # Static WEP, Dynamic WEP, or LEAP
+ wireless_security = WirelessSecurity()
+ wireless_security.key_mgmt = 'none'
+ return wireless_security
+
+ if (self._mode != network.NM_802_11_MODE_INFRA):
+ # Stuff after this point requires infrastructure
+ logging.error('The infrastructure mode is not supoorted'
+ ' by your wireless device.')
+ return None
+
+ if (self._rsn_flags & network.NM_802_11_AP_SEC_KEY_MGMT_PSK) and \
+ (self._device_caps & network.NM_802_11_DEVICE_CAP_RSN):
+ # WPA2 PSK first
+ pairwise = self._add_ciphers_from_flags(self._rsn_flags, True)
+ group = self._add_ciphers_from_flags(self._rsn_flags, False)
+ wireless_security = WirelessSecurity()
+ wireless_security.key_mgmt = 'wpa-psk'
+ wireless_security.proto = 'rsn'
+ wireless_security.pairwise = pairwise
+ wireless_security.group = group
+ return wireless_security
+
+ if (self._wpa_flags & network.NM_802_11_AP_SEC_KEY_MGMT_PSK) and \
+ (self._device_caps & network.NM_802_11_DEVICE_CAP_WPA):
+ # WPA PSK
+ pairwise = self._add_ciphers_from_flags(self._wpa_flags, True)
+ group = self._add_ciphers_from_flags(self._wpa_flags, False)
+ wireless_security = WirelessSecurity()
+ wireless_security.key_mgmt = 'wpa-psk'
+ wireless_security.proto = 'wpa'
+ wireless_security.pairwise = pairwise
+ wireless_security.group = group
+ return wireless_security
+
+ def __connect_activate_cb(self, icon):
+ self._connect()
+
+ def __button_release_event_cb(self, icon, event):
+ self._connect()
+
+ def _connect(self):
+ connection = network.find_connection_by_ssid(self._name)
+ if connection is None:
+ settings = Settings()
+ settings.connection.id = 'Auto ' + self._name
+ uuid = settings.connection.uuid = unique_id()
+ settings.connection.type = '802-11-wireless'
+ settings.wireless.ssid = self._name
+
+ if self._mode == network.NM_802_11_MODE_INFRA:
+ settings.wireless.mode = 'infrastructure'
+ elif self._mode == network.NM_802_11_MODE_ADHOC:
+ settings.wireless.mode = 'adhoc'
+ settings.wireless.band = 'bg'
+ settings.ip4_config = IP4Config()
+ settings.ip4_config.method = 'link-local'
+
+ wireless_security = self._get_security()
+ settings.wireless_security = wireless_security
+
+ if wireless_security is not None:
+ settings.wireless.security = '802-11-wireless-security'
+
+ connection = network.add_connection(uuid, settings)
+
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+
+ netmgr.ActivateConnection(network.SETTINGS_SERVICE, connection.path,
+ self._device.object_path,
+ "/",
+ reply_handler=self.__activate_reply_cb,
+ error_handler=self.__activate_error_cb)
+
+ def __activate_reply_cb(self, connection):
+ logging.debug('Connection activated: %s', connection)
+
+ def __activate_error_cb(self, err):
+ logging.error('Failed to activate connection: %s', err)
+
+ def set_filter(self, query):
+ self._greyed_out = self._name.lower().find(query) == -1
+ self._update_state()
+ self._update_color()
+
+ def create_keydialog(self, settings, response):
+ keydialog.create(self._name, self._flags, self._wpa_flags,
+ self._rsn_flags, self._device_caps, settings, response)
+
+ def update_strength(self):
+ if self._active_ap is not None:
+ # display strength of AP that we are connected to
+ new_strength = self._active_ap.strength
+ else:
+ # display the strength of the strongest AP that makes up this
+ # network, also considering that there may be no APs
+ new_strength = max([0] + [ap.strength for ap in
+ self._access_points.values()])
+
+ if new_strength != self._strength:
+ self._strength = new_strength
+ self._update_state()
+
+ def add_ap(self, ap):
+ self._access_points[ap.model.object_path] = ap
+ self.update_strength()
+
+ def remove_ap(self, ap):
+ path = ap.model.object_path
+ if path not in self._access_points:
+ return
+ del self._access_points[path]
+ if self._active_ap == ap:
+ self._active_ap = None
+ self.update_strength()
+
+ def num_aps(self):
+ return len(self._access_points)
+
+ def find_ap(self, ap_path):
+ if ap_path not in self._access_points:
+ return None
+ return self._access_points[ap_path]
+
+ def is_olpc_mesh(self):
+ return self._mode == network.NM_802_11_MODE_ADHOC \
+ and self.name == "olpc-mesh"
+
+ def remove_all_aps(self):
+ for ap in self._access_points.values():
+ ap.disconnect()
+ self._access_points = {}
+ self._active_ap = None
+ self.update_strength()
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__device_state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+ self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
+class SugarAdhocView(CanvasPulsingIcon):
+ """To mimic the mesh behavior on devices where mesh hardware is
+ not available we support the creation of an Ad-hoc network on
+ three channels 1, 6, 11. This is the class for an icon
+ representing a channel in the neighborhood view.
+
+ """
+
+ _ICON_NAME = 'network-adhoc-'
+ _NAME = 'Ad-hoc Network '
+
+ def __init__(self, channel):
+ CanvasPulsingIcon.__init__(self,
+ icon_name=self._ICON_NAME + str(channel),
+ size=style.STANDARD_ICON_SIZE, cache=True)
+ self._bus = dbus.SystemBus()
+ self._channel = channel
+ self._disconnect_item = None
+ self._connect_item = None
+ self._palette_icon = None
+ self._greyed_out = False
+
+ get_adhoc_manager_instance().connect('members-changed',
+ self.__members_changed_cb)
+ get_adhoc_manager_instance().connect('state-changed',
+ self.__state_changed_cb)
+
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self.props.pulse_color = pulse_color
+ self._state_color = XoColor('%s,%s' % \
+ (profile.get_color().get_stroke_color(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self.props.base_color = self._state_color
+ self._palette = self._create_palette()
+ self.set_palette(self._palette)
+ self._palette_icon.props.xo_color = self._state_color
+
+ def _create_palette(self):
+ self._palette_icon = Icon( \
+ icon_name=self._ICON_NAME + str(self._channel),
+ icon_size=style.STANDARD_ICON_SIZE)
+
+ palette_ = palette.Palette(_("Ad-hoc Network %d") % self._channel,
+ icon=self._palette_icon)
+
+ self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
+ self._connect_item.connect('activate', self.__connect_activate_cb)
+ palette_.menu.append(self._connect_item)
+
+ self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject')
+ self._disconnect_item.connect('activate',
+ self.__disconnect_activate_cb)
+ palette_.menu.append(self._disconnect_item)
+
+ return palette_
+
+ def __button_release_event_cb(self, icon, event):
+ get_adhoc_manager_instance().activate_channel(self._channel)
+
+ def __connect_activate_cb(self, icon):
+ get_adhoc_manager_instance().activate_channel(self._channel)
+
+ def __disconnect_activate_cb(self, icon):
+ get_adhoc_manager_instance().deactivate_active_channel()
+
+ def __state_changed_cb(self, adhoc_manager, channel, device_state):
+ if self._channel == channel:
+ state = device_state
+ else:
+ state = network.DEVICE_STATE_UNKNOWN
+
+ if state == network.DEVICE_STATE_ACTIVATED:
+ icon_name = '%s-connected' % (self._ICON_NAME + str(self._channel))
+ else:
+ icon_name = self._ICON_NAME + str(self._channel)
+
+ self.props.base_color = self._state_color
+ self._palette_icon.props.xo_color = self._state_color
+
+ if icon_name is not None:
+ self.props.icon_name = icon_name
+ icon = self._palette.props.icon
+ icon.props.icon_name = icon_name
+
+ if state in [network.DEVICE_STATE_PREPARE,
+ network.DEVICE_STATE_CONFIG,
+ network.DEVICE_STATE_NEED_AUTH,
+ network.DEVICE_STATE_IP_CONFIG]:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connecting...')
+ self.props.pulsing = True
+ elif state == network.DEVICE_STATE_ACTIVATED:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connected')
+ self.props.pulsing = False
+ else:
+ if self._disconnect_item:
+ self._disconnect_item.hide()
+ self._connect_item.show()
+ self._palette.props.secondary_text = None
+ self.props.pulsing = False
+
+ def _update_color(self):
+ if self._greyed_out:
+ self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
+ else:
+ self.props.base_color = self._state_color
+
+ def __members_changed_cb(self, adhoc_manager, channel, has_members):
+ if channel == self._channel:
+ if has_members == True:
+ self._state_color = profile.get_color()
+ self.props.base_color = self._state_color
+ self._palette_icon.props.xo_color = self._state_color
+ else:
+ color = '%s,%s' % (profile.get_color().get_stroke_color(),
+ style.COLOR_TRANSPARENT.get_svg())
+ self._state_color = XoColor(color)
+ self.props.base_color = self._state_color
+ self._palette_icon.props.xo_color = self._state_color
+
+ def set_filter(self, query):
+ name = self._NAME + str(self._channel)
+ self._greyed_out = name.lower().find(query) == -1
+ self._update_color()
+
+
+class OlpcMeshView(CanvasPulsingIcon):
+ def __init__(self, mesh_mgr, channel):
+ CanvasPulsingIcon.__init__(self, icon_name=_OLPC_MESH_ICON_NAME,
+ size=style.STANDARD_ICON_SIZE, cache=True)
+ self._bus = dbus.SystemBus()
+ self._channel = channel
+ self._mesh_mgr = mesh_mgr
+ self._disconnect_item = None
+ self._connect_item = None
+ self._greyed_out = False
+ self._name = ''
+ self._device_state = None
+ self._connection = None
+ self._active = False
+ device = mesh_mgr.mesh_device
+
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ interface_props = dbus.Interface(device,
+ 'org.freedesktop.DBus.Properties')
+ interface_props.Get(_NM_DEVICE_IFACE, 'State',
+ reply_handler=self.__get_device_state_reply_cb,
+ error_handler=self.__get_device_state_error_cb)
+ interface_props.Get(_NM_OLPC_MESH_IFACE, 'ActiveChannel',
+ reply_handler=self.__get_active_channel_reply_cb,
+ error_handler=self.__get_active_channel_error_cb)
+
+ self._bus.add_signal_receiver(self.__device_state_changed_cb,
+ signal_name='StateChanged',
+ path=device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+ self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=device.object_path,
+ dbus_interface=_NM_OLPC_MESH_IFACE)
+
+ pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self.props.pulse_color = pulse_color
+ self.props.base_color = profile.get_color()
+ self._palette = self._create_palette()
+ self.set_palette(self._palette)
+
+ def _create_palette(self):
+ _palette = palette.Palette(_("Mesh Network %d") % self._channel)
+
+ self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
+ self._connect_item.connect('activate', self.__connect_activate_cb)
+ _palette.menu.append(self._connect_item)
+
+ return _palette
+
+ def __get_device_state_reply_cb(self, state):
+ self._device_state = state
+ self._update()
+
+ def __get_device_state_error_cb(self, err):
+ logging.error('Error getting the device state: %s', err)
+
+ def __device_state_changed_cb(self, new_state, old_state, reason):
+ self._device_state = new_state
+ self._update()
+
+ def __get_active_channel_reply_cb(self, channel):
+ self._active = (channel == self._channel)
+ self._update()
+
+ def __get_active_channel_error_cb(self, err):
+ logging.error('Error getting the active channel: %s', err)
+
+ def __wireless_properties_changed_cb(self, properties):
+ if 'ActiveChannel' in properties:
+ channel = properties['ActiveChannel']
+ self._active = (channel == self._channel)
+ self._update()
+
+ def _update(self):
+ if self._active:
+ state = self._device_state
+ else:
+ state = network.DEVICE_STATE_UNKNOWN
+
+ if state in [network.DEVICE_STATE_PREPARE,
+ network.DEVICE_STATE_CONFIG,
+ network.DEVICE_STATE_NEED_AUTH,
+ network.DEVICE_STATE_IP_CONFIG]:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connecting...')
+ self.props.pulsing = True
+ elif state == network.DEVICE_STATE_ACTIVATED:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connected')
+ self.props.pulsing = False
+ else:
+ if self._disconnect_item:
+ self._disconnect_item.hide()
+ self._connect_item.show()
+ self._palette.props.secondary_text = None
+ self.props.pulsing = False
+
+ def _update_color(self):
+ if self._greyed_out:
+ self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
+ else:
+ self.props.base_color = profile.get_color()
+
+ def __connect_activate_cb(self, icon):
+ self._connect()
+
+ def __button_release_event_cb(self, icon, event):
+ self._connect()
+
+ def _connect(self):
+ self._mesh_mgr.user_activate_channel(self._channel)
+
+ def __activate_reply_cb(self, connection):
+ logging.debug('Connection activated: %s', connection)
+
+ def __activate_error_cb(self, err):
+ logging.error('Failed to activate connection: %s', err)
+
+ def set_filter(self, query):
+ self._greyed_out = (query != '')
+ self._update_color()
+
+ def disconnect(self):
+ device_object_path = self._mesh_mgr.mesh_device.object_path
+
+ self._bus.remove_signal_receiver(self.__device_state_changed_cb,
+ signal_name='StateChanged',
+ path=device_object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+ self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=device_object_path,
+ dbus_interface=_NM_OLPC_MESH_IFACE)
+
diff --git a/shell/src/jarabe/desktop/schoolserver.py b/shell/src/jarabe/desktop/schoolserver.py
new file mode 100644
index 0000000..a05f56c
--- /dev/null
+++ b/shell/src/jarabe/desktop/schoolserver.py
@@ -0,0 +1,127 @@
+# Copyright (C) 2007, 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+from xmlrpclib import ServerProxy, Error
+import socket
+import os
+from string import ascii_uppercase
+import random
+import time
+import uuid
+
+import gconf
+
+from sugar import env
+from sugar.profile import get_profile
+
+REGISTER_URL = 'http://schoolserver:8080/'
+
+def generate_serial_number():
+ """ Generates a serial number based on 3 random uppercase letters
+ and the last 8 digits of the current unix seconds. """
+
+ serial_part1 = []
+
+ for y_ in range(3) :
+ serial_part1.append(random.choice(ascii_uppercase))
+
+ serial_part1 = ''.join(serial_part1)
+ serial_part2 = str(int(time.time()))[-8:]
+ serial = serial_part1 + serial_part2
+
+ return serial
+
+def store_identifiers(serial_number, uuid, backup_url):
+ """ Stores the serial number, uuid and backup_url
+ in the identifier folder inside the profile directory
+ so that these identifiers can be used for backup. """
+
+ identifier_path = os.path.join(env.get_profile_path(), 'identifiers')
+ if not os.path.exists(identifier_path):
+ os.mkdir(identifier_path)
+
+ if os.path.exists(os.path.join(identifier_path, 'sn')):
+ os.remove(os.path.join(identifier_path, 'sn'))
+ serial_file = open(os.path.join(identifier_path, 'sn'), 'w')
+ serial_file.write(serial_number)
+ serial_file.close()
+
+ if os.path.exists(os.path.join(identifier_path, 'uuid')):
+ os.remove(os.path.join(identifier_path, 'uuid'))
+ uuid_file = open(os.path.join(identifier_path, 'uuid'), 'w')
+ uuid_file.write(uuid)
+ uuid_file.close()
+
+ if os.path.exists(os.path.join(identifier_path, 'backup_url')):
+ os.remove(os.path.join(identifier_path, 'backup_url'))
+ backup_url_file = open(os.path.join(identifier_path, 'backup_url'), 'w')
+ backup_url_file.write(backup_url)
+ backup_url_file.close()
+
+class RegisterError(Exception):
+ pass
+
+def register_laptop(url=REGISTER_URL):
+
+ profile = get_profile()
+ client = gconf.client_get_default()
+
+ if have_ofw_tree():
+ sn = read_ofw('mfg-data/SN')
+ uuid_ = read_ofw('mfg-data/U#')
+ sn = sn or 'SHF00000000'
+ uuid_ = uuid_ or '00000000-0000-0000-0000-000000000000'
+ else:
+ sn = generate_serial_number()
+ uuid_ = str(uuid.uuid1())
+ setting_name = '/desktop/sugar/collaboration/jabber_server'
+ jabber_server = client.get_string(setting_name)
+ store_identifiers(sn, uuid_, jabber_server)
+ url = 'http://' + jabber_server + ':8080/'
+
+ nick = client.get_string('/desktop/sugar/user/nick')
+
+ server = ServerProxy(url)
+ try:
+ data = server.register(sn, nick, uuid_, profile.pubkey)
+ except (Error, TypeError, socket.error):
+ logging.exception('Registration: cannot connect to server')
+ raise RegisterError(_('Cannot connect to the server.'))
+
+ if data['success'] != 'OK':
+ logging.error('Registration: server could not complete request: %s',
+ data['error'])
+ raise RegisterError(_('The server could not complete the request.'))
+
+ client.set_string('/desktop/sugar/collaboration/jabber_server',
+ data['jabberserver'])
+ client.set_string('/desktop/sugar/backup_url', data['backupurl'])
+
+ return True
+
+def have_ofw_tree():
+ return os.path.exists('/ofw')
+
+def read_ofw(path):
+ path = os.path.join('/ofw', path)
+ if not os.path.exists(path):
+ return None
+ fh = open(path, 'r')
+ data = fh.read().rstrip('\0\n')
+ fh.close()
+ return data
diff --git a/shell/src/jarabe/desktop/snowflakelayout.py b/shell/src/jarabe/desktop/snowflakelayout.py
new file mode 100644
index 0000000..5782cff
--- /dev/null
+++ b/shell/src/jarabe/desktop/snowflakelayout.py
@@ -0,0 +1,108 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import math
+
+import gobject
+import hippo
+
+from sugar.graphics import style
+
+_BASE_DISTANCE = style.zoom(25)
+_CHILDREN_FACTOR = style.zoom(3)
+
+class SnowflakeLayout(gobject.GObject, hippo.CanvasLayout):
+ __gtype_name__ = 'SugarSnowflakeLayout'
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self._nflakes = 0
+ self._box = None
+
+ def add(self, child, center=False):
+ if not center:
+ self._nflakes += 1
+
+ self._box.append(child)
+
+ box_child = self._box.find_box_child(child)
+ box_child.is_center = center
+
+ def remove(self, child):
+ box_child = self._box.find_box_child(child)
+ if not box_child.is_center:
+ self._nflakes -= 1
+
+ self._box.remove(child)
+
+ def do_set_box(self, box):
+ self._box = box
+
+ def do_get_height_request(self, for_width):
+ size = self._calculate_size()
+ return (size, size)
+
+ def do_get_width_request(self):
+ size = self._calculate_size()
+ return (size, size)
+
+ def do_allocate(self, x, y, width, height,
+ req_width, req_height, origin_changed):
+ r = self._get_radius()
+ index = 0
+
+ for child in self._box.get_layout_children():
+ min_width, child_width = child.get_width_request()
+ min_height, child_height = child.get_height_request(child_width)
+
+ if child.is_center:
+ child.allocate(x + (width - child_width) / 2,
+ y + (height - child_height) / 2,
+ child_width, child_height, origin_changed)
+ else:
+ angle = 2 * math.pi * index / self._nflakes
+
+ if self._nflakes != 2:
+ angle -= math.pi / 2
+
+ dx = math.cos(angle) * r
+ dy = math.sin(angle) * r
+
+ child_x = int(x + (width - child_width) / 2 + dx)
+ child_y = int(y + (height - child_height) / 2 + dy)
+
+ child.allocate(child_x, child_y, child_width,
+ child_height, origin_changed)
+
+ index += 1
+
+ def _get_radius(self):
+ radius = int(_BASE_DISTANCE + _CHILDREN_FACTOR * self._nflakes)
+ for child in self._box.get_layout_children():
+ if child.is_center:
+ [min_w, child_w] = child.get_width_request()
+ [min_h, child_h] = child.get_height_request(child_w)
+ radius += max(child_w, child_h) / 2
+
+ return radius
+
+ def _calculate_size(self):
+ thickness = 0
+ for child in self._box.get_layout_children():
+ [min_width, child_width] = child.get_width_request()
+ [min_height, child_height] = child.get_height_request(child_width)
+ thickness = max(thickness, max(child_width, child_height))
+
+ return self._get_radius() * 2 + thickness
diff --git a/shell/src/jarabe/desktop/spreadlayout.py b/shell/src/jarabe/desktop/spreadlayout.py
new file mode 100644
index 0000000..ffc5bc7
--- /dev/null
+++ b/shell/src/jarabe/desktop/spreadlayout.py
@@ -0,0 +1,83 @@
+# Copyright (C) 2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import hippo
+import gobject
+import gtk
+
+from sugar.graphics import style
+
+from jarabe.desktop.grid import Grid
+
+_CELL_SIZE = 4.0
+
+class SpreadLayout(gobject.GObject, hippo.CanvasLayout):
+ __gtype_name__ = 'SugarSpreadLayout'
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self._box = None
+
+ min_width, width = self.do_get_width_request()
+ min_height, height = self.do_get_height_request(width)
+
+ self._grid = Grid(int(width / _CELL_SIZE), int(height / _CELL_SIZE))
+ self._grid.connect('child-changed', self._grid_child_changed_cb)
+
+ def add(self, child):
+ self._box.append(child)
+
+ width, height = self._get_child_grid_size(child)
+ self._grid.add(child, width, height)
+
+ def remove(self, child):
+ self._grid.remove(child)
+ self._box.remove(child)
+
+ def move(self, child, x, y):
+ self._grid.move(child, x / _CELL_SIZE, y / _CELL_SIZE, locked=True)
+
+ def do_set_box(self, box):
+ self._box = box
+
+ def do_get_height_request(self, for_width):
+ return 0, gtk.gdk.screen_height() - style.GRID_CELL_SIZE
+
+ def do_get_width_request(self):
+ return 0, gtk.gdk.screen_width()
+
+ def do_allocate(self, x, y, width, height,
+ req_width, req_height, origin_changed):
+ for child in self._box.get_layout_children():
+ # We need to always get requests to not confuse hippo
+ min_w, child_width = child.get_width_request()
+ min_h, child_height = child.get_height_request(child_width)
+
+ rect = self._grid.get_child_rect(child.item)
+ child.allocate(int(round(rect.x * _CELL_SIZE)),
+ int(round(rect.y * _CELL_SIZE)),
+ child_width,
+ child_height,
+ origin_changed)
+
+ def _get_child_grid_size(self, child):
+ min_width, width = child.get_width_request()
+ min_height, height = child.get_height_request(width)
+
+ return int(width / _CELL_SIZE), int(height / _CELL_SIZE)
+
+ def _grid_child_changed_cb(self, grid, child):
+ child.emit_request_changed()
+
diff --git a/shell/src/jarabe/desktop/transitionbox.py b/shell/src/jarabe/desktop/transitionbox.py
new file mode 100644
index 0000000..cf9e0d6
--- /dev/null
+++ b/shell/src/jarabe/desktop/transitionbox.py
@@ -0,0 +1,96 @@
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import hippo
+import gobject
+
+from sugar.graphics import style
+from sugar.graphics import animator
+
+from jarabe.model.buddy import get_owner_instance
+from jarabe.view.buddyicon import BuddyIcon
+
+class _Animation(animator.Animation):
+ def __init__(self, icon, start_size, end_size):
+ animator.Animation.__init__(self, 0.0, 1.0)
+
+ self._icon = icon
+ self.start_size = start_size
+ self.end_size = end_size
+
+ def next_frame(self, current):
+ d = (self.end_size - self.start_size) * current
+ self._icon.props.size = self.start_size + d
+
+class _Layout(gobject.GObject, hippo.CanvasLayout):
+ __gtype_name__ = 'SugarTransitionBoxLayout'
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self._box = None
+
+ def do_set_box(self, box):
+ self._box = box
+
+ def do_get_height_request(self, for_width):
+ return 0, 0
+
+ def do_get_width_request(self):
+ return 0, 0
+
+ def do_allocate(self, x, y, width, height,
+ req_width, req_height, origin_changed):
+ for child in self._box.get_layout_children():
+ min_width, child_width = child.get_width_request()
+ min_height, child_height = child.get_height_request(child_width)
+
+ child.allocate(x + (width - child_width) / 2,
+ y + (height - child_height) / 2,
+ child_width, child_height, origin_changed)
+
+class TransitionBox(hippo.Canvas):
+ __gtype_name__ = 'SugarTransitionBox'
+
+ __gsignals__ = {
+ 'completed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._box = hippo.CanvasBox()
+ self._box.props.background_color = style.COLOR_WHITE.get_int()
+ self.set_root(self._box)
+
+ self._layout = _Layout()
+ self._box.set_layout(self._layout)
+
+ self._my_icon = BuddyIcon(buddy=get_owner_instance(),
+ size=style.XLARGE_ICON_SIZE)
+ self._box.append(self._my_icon)
+
+ self._animator = animator.Animator(0.3)
+ self._animator.connect('completed', self._animation_completed_cb)
+
+ def _animation_completed_cb(self, anim):
+ self.emit('completed')
+
+ def start_transition(self, start_size, end_size):
+ self._my_icon.props.size = start_size
+
+ self._animator.remove_all()
+ self._animator.add(_Animation(self._my_icon, start_size, end_size))
+ self._animator.start()
diff --git a/shell/src/jarabe/frame/Makefile.am b/shell/src/jarabe/frame/Makefile.am
new file mode 100644
index 0000000..e5c445f
--- /dev/null
+++ b/shell/src/jarabe/frame/Makefile.am
@@ -0,0 +1,18 @@
+sugardir = $(pythondir)/jarabe/frame
+sugar_PYTHON = \
+ __init__.py \
+ activitiestray.py \
+ clipboard.py \
+ clipboardicon.py \
+ clipboardmenu.py \
+ clipboardobject.py \
+ clipboardpanelwindow.py \
+ clipboardtray.py \
+ devicestray.py \
+ frameinvoker.py \
+ friendstray.py \
+ eventarea.py \
+ frame.py \
+ notification.py \
+ framewindow.py \
+ zoomtoolbar.py
diff --git a/shell/src/jarabe/frame/__init__.py b/shell/src/jarabe/frame/__init__.py
new file mode 100644
index 0000000..d7aec3d
--- /dev/null
+++ b/shell/src/jarabe/frame/__init__.py
@@ -0,0 +1,25 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from jarabe.frame.frame import Frame
+
+_view = None
+
+def get_view():
+ global _view
+ if not _view:
+ _view = Frame()
+ return _view
diff --git a/shell/src/jarabe/frame/activitiestray.py b/shell/src/jarabe/frame/activitiestray.py
new file mode 100644
index 0000000..9a1a9da
--- /dev/null
+++ b/shell/src/jarabe/frame/activitiestray.py
@@ -0,0 +1,745 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2008 One Laptop Per Child
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+import tempfile
+import os
+
+import gobject
+import gconf
+import gio
+import gtk
+
+from sugar.graphics import style
+from sugar.graphics.tray import HTray
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.radiotoolbutton import RadioToolButton
+from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics.icon import Icon, get_icon_file_name
+from sugar.graphics.palette import Palette, WidgetInvoker
+from sugar.graphics.menuitem import MenuItem
+from sugar.datastore import datastore
+from sugar import mime
+from sugar import env
+
+from jarabe.model import shell
+from jarabe.model import invites
+from jarabe.model import bundleregistry
+from jarabe.model import filetransfer
+from jarabe.view.palettes import JournalPalette, CurrentActivityPalette
+from jarabe.view.pulsingicon import PulsingIcon
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+from jarabe.frame.notification import NotificationIcon
+import jarabe.frame
+
+
+class ActivityButton(RadioToolButton):
+ def __init__(self, home_activity, group):
+ RadioToolButton.__init__(self, group=group)
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+
+ self._home_activity = home_activity
+ self._notify_launch_hid = None
+
+ self._icon = PulsingIcon()
+ self._icon.props.base_color = home_activity.get_icon_color()
+ self._icon.props.pulse_color = \
+ XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TOOLBAR_GREY.get_svg()))
+ if home_activity.get_icon_path():
+ self._icon.props.file = home_activity.get_icon_path()
+ else:
+ self._icon.props.icon_name = 'image-missing'
+ self.set_icon_widget(self._icon)
+ self._icon.show()
+
+ if home_activity.props.launch_status == shell.Activity.LAUNCHING:
+ self._icon.props.pulsing = True
+ self._notify_launch_hid = home_activity.connect( \
+ 'notify::launch-status', self.__notify_launch_status_cb)
+ elif home_activity.props.launch_status == shell.Activity.LAUNCH_FAILED:
+ self._on_failed_launch()
+
+ def create_palette(self):
+ if self._home_activity.is_journal():
+ palette = JournalPalette(self._home_activity)
+ else:
+ palette = CurrentActivityPalette(self._home_activity)
+ palette.set_group_id('frame')
+ self.set_palette(palette)
+
+ def _on_failed_launch(self):
+ # TODO http://bugs.sugarlabs.org/ticket/2007
+ pass
+
+ def __notify_launch_status_cb(self, home_activity, pspec):
+ home_activity.disconnect(self._notify_launch_hid)
+ self._notify_launch_hid = None
+ if home_activity.props.launch_status == shell.Activity.LAUNCH_FAILED:
+ self._on_failed_launch()
+ else:
+ self._icon.props.pulsing = False
+
+
+
+class InviteButton(ToolButton):
+ """Invite to shared activity"""
+ def __init__(self, invite):
+ ToolButton.__init__(self)
+
+ self._invite = invite
+
+ self.connect('clicked', self.__clicked_cb)
+ self.connect('destroy', self.__destroy_cb)
+
+ bundle_registry = bundleregistry.get_registry()
+ bundle = bundle_registry.get_bundle(invite.get_bundle_id())
+
+ self._icon = Icon()
+ self._icon.props.xo_color = invite.get_color()
+ if bundle is not None:
+ self._icon.props.file = bundle.get_icon()
+ else:
+ self._icon.props.icon_name = 'image-missing'
+ self.set_icon_widget(self._icon)
+ self._icon.show()
+
+ palette = InvitePalette(invite)
+ palette.props.invoker = FrameWidgetInvoker(self)
+ palette.set_group_id('frame')
+ self.set_palette(palette)
+
+ self._notif_icon = NotificationIcon()
+ self._notif_icon.connect('button-release-event',
+ self.__button_release_event_cb)
+
+ self._notif_icon.props.xo_color = invite.get_color()
+ if bundle is not None:
+ self._notif_icon.props.icon_filename = bundle.get_icon()
+ else:
+ self._notif_icon.props.icon_name = 'image-missing'
+
+ palette = InvitePalette(invite)
+ palette.props.invoker = WidgetInvoker(self._notif_icon)
+ palette.set_group_id('frame')
+ self._notif_icon.palette = palette
+
+ frame = jarabe.frame.get_view()
+ frame.add_notification(self._notif_icon, gtk.CORNER_TOP_LEFT)
+
+ def __button_release_event_cb(self, icon, event):
+ self.emit('clicked')
+
+ def __clicked_cb(self, button):
+ if self._notif_icon is not None:
+ frame = jarabe.frame.get_view()
+ frame.remove_notification(self._notif_icon)
+ self._notif_icon = None
+ self._launch()
+
+ def __destroy_cb(self, button):
+ frame = jarabe.frame.get_view()
+ frame.remove_notification(self._notif_icon)
+
+ def _launch(self):
+ """Join the activity in the invite."""
+ self._invite.join()
+
+
+class InvitePalette(Palette):
+ """Palette for frame or notification icon for invites."""
+
+ def __init__(self, invite):
+ Palette.__init__(self, '')
+
+ self._invite = invite
+
+ menu_item = MenuItem(_('Join'), icon_name='dialog-ok')
+ menu_item.connect('activate', self.__join_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ menu_item = MenuItem(_('Decline'), icon_name='dialog-cancel')
+ menu_item.connect('activate', self.__decline_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ bundle_id = invite.get_bundle_id()
+
+ registry = bundleregistry.get_registry()
+ self._bundle = registry.get_bundle(bundle_id)
+ if self._bundle:
+ self.set_primary_text(self._bundle.get_name())
+ else:
+ self.set_primary_text(bundle_id)
+
+ def __join_activate_cb(self, menu_item):
+ self._invite.join()
+
+ def __decline_activate_cb(self, menu_item):
+ invites_model = invites.get_instance()
+ activity_id = self._activity_model.get_id()
+ invites_model.remove_activity(activity_id)
+
+
+class ActivitiesTray(HTray):
+ def __init__(self):
+ HTray.__init__(self)
+
+ self._buttons = {}
+ self._invite_to_item = {}
+ self._freeze_button_clicks = False
+
+ self._home_model = shell.get_model()
+ self._home_model.connect('activity-added', self.__activity_added_cb)
+ self._home_model.connect('activity-removed', self.__activity_removed_cb)
+ self._home_model.connect('active-activity-changed',
+ self.__activity_changed_cb)
+ self._home_model.connect('tabbing-activity-changed',
+ self.__tabbing_activity_changed_cb)
+
+ self._invites = invites.get_instance()
+ for invite in self._invites:
+ self._add_invite(invite)
+ self._invites.connect('invite-added', self.__invite_added_cb)
+ self._invites.connect('invite-removed', self.__invite_removed_cb)
+
+ filetransfer.new_file_transfer.connect(self.__new_file_transfer_cb)
+
+ def __activity_added_cb(self, home_model, home_activity):
+ logging.debug('__activity_added_cb: %r', home_activity)
+ if self.get_children():
+ group = self.get_children()[0]
+ else:
+ group = None
+
+ button = ActivityButton(home_activity, group)
+ self.add_item(button)
+ self._buttons[home_activity] = button
+ button.connect('clicked', self.__activity_clicked_cb, home_activity)
+ button.show()
+
+ def __activity_removed_cb(self, home_model, home_activity):
+ logging.debug('__activity_removed_cb: %r', home_activity)
+ button = self._buttons[home_activity]
+ self.remove_item(button)
+ del self._buttons[home_activity]
+
+ def _activate_activity(self, home_activity):
+ button = self._buttons[home_activity]
+ self._freeze_button_clicks = True
+ button.props.active = True
+ self._freeze_button_clicks = False
+
+ self.scroll_to_item(button)
+ # Redraw immediately.
+ # The widget may not be realized yet, and then there is no window.
+ if self.window:
+ self.window.process_updates(True)
+
+ def __activity_changed_cb(self, home_model, home_activity):
+ logging.debug('__activity_changed_cb: %r', home_activity)
+
+ # Only select the new activity, if there is no tabbing activity.
+ if home_model.get_tabbing_activity() is None:
+ self._activate_activity(home_activity)
+
+ def __tabbing_activity_changed_cb(self, home_model, home_activity):
+ logging.debug('__tabbing_activity_changed_cb: %r', home_activity)
+ # If the tabbing_activity is set to None just do nothing.
+ # The active activity will be updated a bit later (and it will
+ # be set to the activity that is currently selected).
+ if home_activity is None:
+ return
+
+ self._activate_activity(home_activity)
+
+ def __activity_clicked_cb(self, button, home_activity):
+ if not self._freeze_button_clicks and button.props.active:
+ logging.debug('ActivitiesTray.__activity_clicked_cb')
+ window = home_activity.get_window()
+ if window:
+ window.activate(gtk.get_current_event_time())
+
+ def __invite_clicked_cb(self, icon, invite):
+ self._invites.remove_invite(invite)
+
+ def __invite_added_cb(self, invites_model, invite):
+ self._add_invite(invite)
+
+ def __invite_removed_cb(self, invites_model, invite):
+ self._remove_invite(invite)
+
+ def _add_invite(self, invite):
+ """Add an invite"""
+ item = InviteButton(invite)
+ item.connect('clicked', self.__invite_clicked_cb, invite)
+ self.add_item(item)
+ item.show()
+
+ self._invite_to_item[invite] = item
+
+ def _remove_invite(self, invite):
+ self.remove_item(self._invite_to_item[invite])
+ self._invite_to_item[invite].destroy()
+ del self._invite_to_item[invite]
+
+ def __new_file_transfer_cb(self, **kwargs):
+ file_transfer = kwargs['file_transfer']
+ logging.debug('__new_file_transfer_cb %r', file_transfer)
+
+ if isinstance(file_transfer, filetransfer.IncomingFileTransfer):
+ button = IncomingTransferButton(file_transfer)
+ elif isinstance(file_transfer, filetransfer.OutgoingFileTransfer):
+ button = OutgoingTransferButton(file_transfer)
+
+ self.add_item(button)
+ button.show()
+
+class BaseTransferButton(ToolButton):
+ """Button with a notification attached
+ """
+ def __init__(self, file_transfer):
+ ToolButton.__init__(self)
+
+ self.file_transfer = file_transfer
+ file_transfer.connect('notify::state', self.__notify_state_cb)
+
+ icon = Icon()
+ self.props.icon_widget = icon
+ icon.show()
+
+ self.notif_icon = NotificationIcon()
+ self.notif_icon.connect('button-release-event',
+ self.__button_release_event_cb)
+
+ def __button_release_event_cb(self, icon, event):
+ if self.notif_icon is not None:
+ frame = jarabe.frame.get_view()
+ frame.remove_notification(self.notif_icon)
+ self.notif_icon = None
+
+ def remove(self):
+ frame = jarabe.frame.get_view()
+ frame.remove_notification(self.notif_icon)
+ self.props.parent.remove(self)
+
+ def __notify_state_cb(self, file_transfer, pspec):
+ logging.debug('_update state: %r %r', file_transfer.props.state,
+ file_transfer.reason_last_change)
+ if file_transfer.props.state == filetransfer.FT_STATE_CANCELLED:
+ if file_transfer.reason_last_change == \
+ filetransfer.FT_REASON_LOCAL_STOPPED:
+ self.remove()
+
+class IncomingTransferButton(BaseTransferButton):
+ """UI element representing an ongoing incoming file transfer
+ """
+ def __init__(self, file_transfer):
+ BaseTransferButton.__init__(self, file_transfer)
+
+ self._ds_object = datastore.create()
+
+ file_transfer.connect('notify::state', self.__notify_state_cb)
+ file_transfer.connect('notify::transferred-bytes',
+ self.__notify_transferred_bytes_cb)
+
+ icons = gio.content_type_get_icon(file_transfer.mime_type).props.names
+ icons.append('application-octet-stream')
+ for icon_name in icons:
+ icon_name = 'transfer-from-%s' % icon_name
+ file_name = get_icon_file_name(icon_name)
+ if file_name is not None:
+ self.props.icon_widget.props.icon_name = icon_name
+ self.notif_icon.props.icon_name = icon_name
+ break
+
+ icon_color = XoColor(file_transfer.buddy.props.color)
+ self.props.icon_widget.props.xo_color = icon_color
+ self.notif_icon.props.xo_color = icon_color
+
+ frame = jarabe.frame.get_view()
+ frame.add_notification(self.notif_icon,
+ gtk.CORNER_TOP_LEFT)
+
+ def create_palette(self):
+ palette = IncomingTransferPalette(self.file_transfer)
+ palette.connect('dismiss-clicked', self.__dismiss_clicked_cb)
+ palette.props.invoker = FrameWidgetInvoker(self)
+ palette.set_group_id('frame')
+ return palette
+
+ def __notify_state_cb(self, file_transfer, pspec):
+ if file_transfer.props.state == filetransfer.FT_STATE_OPEN:
+ logging.debug('__notify_state_cb OPEN')
+ self._ds_object.metadata['title'] = file_transfer.title
+ self._ds_object.metadata['description'] = file_transfer.description
+ self._ds_object.metadata['progress'] = '0'
+ self._ds_object.metadata['keep'] = '0'
+ self._ds_object.metadata['buddies'] = ''
+ self._ds_object.metadata['preview'] = ''
+ self._ds_object.metadata['icon-color'] = \
+ file_transfer.buddy.props.color
+ self._ds_object.metadata['mime_type'] = file_transfer.mime_type
+ elif file_transfer.props.state == filetransfer.FT_STATE_COMPLETED:
+ logging.debug('__notify_state_cb COMPLETED')
+ self._ds_object.metadata['progress'] = '100'
+ self._ds_object.file_path = file_transfer.destination_path
+ datastore.write(self._ds_object, transfer_ownership=True,
+ reply_handler=self.__reply_handler_cb,
+ error_handler=self.__error_handler_cb)
+ elif file_transfer.props.state == filetransfer.FT_STATE_CANCELLED:
+ logging.debug('__notify_state_cb CANCELLED')
+ object_id = self._ds_object.object_id
+ if object_id is not None:
+ self._ds_object.destroy()
+ datastore.delete(object_id)
+ self._ds_object = None
+
+ def __notify_transferred_bytes_cb(self, file_transfer, pspec):
+ progress = file_transfer.props.transferred_bytes / \
+ file_transfer.file_size
+ self._ds_object.metadata['progress'] = str(progress * 100)
+ datastore.write(self._ds_object, update_mtime=False)
+
+ def __reply_handler_cb(self):
+ logging.debug('__reply_handler_cb %r', self._ds_object.object_id)
+
+ def __error_handler_cb(self, error):
+ logging.debug('__error_handler_cb %r %s', self._ds_object.object_id,
+ error)
+
+ def __dismiss_clicked_cb(self, palette):
+ self.remove()
+
+class OutgoingTransferButton(BaseTransferButton):
+ """UI element representing an ongoing outgoing file transfer
+ """
+ def __init__(self, file_transfer):
+ BaseTransferButton.__init__(self, file_transfer)
+
+ icons = gio.content_type_get_icon(file_transfer.mime_type).props.names
+ icons.append('application-octet-stream')
+ for icon_name in icons:
+ icon_name = 'transfer-to-%s' % icon_name
+ file_name = get_icon_file_name(icon_name)
+ if file_name is not None:
+ self.props.icon_widget.props.icon_name = icon_name
+ self.notif_icon.props.icon_name = icon_name
+ break
+
+ client = gconf.client_get_default()
+ icon_color = XoColor(client.get_string("/desktop/sugar/user/color"))
+ self.props.icon_widget.props.xo_color = icon_color
+ self.notif_icon.props.xo_color = icon_color
+
+ frame = jarabe.frame.get_view()
+ frame.add_notification(self.notif_icon,
+ gtk.CORNER_TOP_LEFT)
+
+ def create_palette(self):
+ palette = OutgoingTransferPalette(self.file_transfer)
+ palette.connect('dismiss-clicked', self.__dismiss_clicked_cb)
+ palette.props.invoker = FrameWidgetInvoker(self)
+ palette.set_group_id('frame')
+ return palette
+
+ def __dismiss_clicked_cb(self, palette):
+ self.remove()
+
+class BaseTransferPalette(Palette):
+ """Base palette class for frame or notification icon for file transfers
+ """
+ __gtype_name__ = "SugarBaseTransferPalette"
+
+ __gsignals__ = {
+ 'dismiss-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ }
+
+ def __init__(self, file_transfer):
+ Palette.__init__(self, file_transfer.title)
+
+ self.file_transfer = file_transfer
+
+ self.progress_bar = None
+ self.progress_label = None
+ self._notify_transferred_bytes_handler = None
+
+ self.connect('popup', self.__popup_cb)
+ self.connect('popdown', self.__popdown_cb)
+
+ def __popup_cb(self, palette):
+ self.update_progress()
+ self._notify_transferred_bytes_handler = \
+ self.file_transfer.connect('notify::transferred_bytes',
+ self.__notify_transferred_bytes_cb)
+
+ def __popdown_cb(self, palette):
+ if self._notify_transferred_bytes_handler is not None:
+ self.file_transfer.disconnect(
+ self._notify_transferred_bytes_handler)
+ self._notify_transferred_bytes_handler = None
+
+ def __notify_transferred_bytes_cb(self, file_transfer, pspec):
+ self.update_progress()
+
+ def _format_size(self, size):
+ if size < 1024:
+ return _('%dB') % size
+ elif size < 1048576:
+ return _('%dKB') % (size / 1024)
+ else:
+ return _('%dMB') % (size / 1048576)
+
+ def update_progress(self):
+ logging.debug('update_progress: %r',
+ self.file_transfer.props.transferred_bytes)
+
+ if self.progress_bar is None:
+ return
+
+ self.progress_bar.props.fraction = \
+ self.file_transfer.props.transferred_bytes / \
+ float(self.file_transfer.file_size)
+ logging.debug('update_progress: %r', self.progress_bar.props.fraction)
+
+ transferred = self._format_size(
+ self.file_transfer.props.transferred_bytes)
+ total = self._format_size(self.file_transfer.file_size)
+ self.progress_label.props.label = _('%s of %s') % (transferred, total)
+
+class IncomingTransferPalette(BaseTransferPalette):
+ """Palette for frame or notification icon for incoming file transfers
+ """
+ __gtype_name__ = "SugarIncomingTransferPalette"
+ def __init__(self, file_transfer):
+ BaseTransferPalette.__init__(self, file_transfer)
+
+ self.file_transfer.connect('notify::state', self.__notify_state_cb)
+
+ nick = self.file_transfer.buddy.props.nick
+ self.props.secondary_text = _('Transfer from %r') % nick
+
+ self._update()
+
+ def __notify_state_cb(self, file_transfer, pspec):
+ self._update()
+
+ def _update(self):
+ logging.debug('_update state: %r', self.file_transfer.props.state)
+ if self.file_transfer.props.state == filetransfer.FT_STATE_PENDING:
+ menu_item = MenuItem(_('Accept'), icon_name='dialog-ok')
+ menu_item.connect('activate', self.__accept_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ menu_item = MenuItem(_('Decline'), icon_name='dialog-cancel')
+ menu_item.connect('activate', self.__decline_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+ vbox.show()
+
+ if self.file_transfer.description:
+ label = gtk.Label(self.file_transfer.description)
+ vbox.add(label)
+ label.show()
+
+ mime_type = self.file_transfer.mime_type
+ type_description = mime.get_mime_description(mime_type)
+
+ size = self._format_size(self.file_transfer.file_size)
+ label = gtk.Label(_('%s (%s)') % (size, type_description))
+ vbox.add(label)
+ label.show()
+
+ elif self.file_transfer.props.state in \
+ [filetransfer.FT_STATE_ACCEPTED, filetransfer.FT_STATE_OPEN]:
+
+ for item in self.menu.get_children():
+ self.menu.remove(item)
+
+ menu_item = MenuItem(_('Cancel'), icon_name='dialog-cancel')
+ menu_item.connect('activate', self.__cancel_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+ vbox.show()
+
+ self.progress_bar = gtk.ProgressBar()
+ vbox.add(self.progress_bar)
+ self.progress_bar.show()
+
+ self.progress_label = gtk.Label('')
+ vbox.add(self.progress_label)
+ self.progress_label.show()
+
+ self.update_progress()
+
+ elif self.file_transfer.props.state == filetransfer.FT_STATE_COMPLETED:
+
+ for item in self.menu.get_children():
+ self.menu.remove(item)
+
+ menu_item = MenuItem(_('Dismiss'), icon_name='dialog-cancel')
+ menu_item.connect('activate', self.__dismiss_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ self.update_progress()
+ elif self.file_transfer.props.state == filetransfer.FT_STATE_CANCELLED:
+
+ for item in self.menu.get_children():
+ self.menu.remove(item)
+
+ menu_item = MenuItem(_('Resume'), icon_name='dialog-cancel')
+ menu_item.connect('activate', self.__resume_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ self.update_progress()
+
+ def __accept_activate_cb(self, menu_item):
+ #TODO: figure out the best place to get rid of that temp file
+ extension = mime.get_primary_extension(self.file_transfer.mime_type)
+ if extension is None:
+ extension = '.bin'
+ fd, file_path = tempfile.mkstemp(suffix=extension,
+ prefix=self._sanitize(self.file_transfer.title),
+ dir=os.path.join(env.get_profile_path(), 'data'))
+ os.close(fd)
+ os.unlink(file_path)
+
+ self.file_transfer.accept(file_path)
+
+ def _sanitize(self, file_name):
+ file_name = file_name.replace('/', '_')
+ file_name = file_name.replace('.', '_')
+ file_name = file_name.replace('?', '_')
+ return file_name
+
+ def __decline_activate_cb(self, menu_item):
+ self.file_transfer.cancel()
+
+ def __cancel_activate_cb(self, menu_item):
+ self.file_transfer.cancel()
+
+ def __resume_activate_cb(self, menu_item):
+ self.file_transfer.resume()
+
+ def __dismiss_activate_cb(self, menu_item):
+ self.emit('dismiss-clicked')
+
+class OutgoingTransferPalette(BaseTransferPalette):
+ """Palette for frame or notification icon for outgoing file transfers
+ """
+ __gtype_name__ = "SugarOutgoingTransferPalette"
+
+ def __init__(self, file_transfer):
+ BaseTransferPalette.__init__(self, file_transfer)
+
+ self.progress_bar = None
+ self.progress_label = None
+
+ self.file_transfer.connect('notify::state', self.__notify_state_cb)
+
+ nick = file_transfer.buddy.props.nick
+ self.props.secondary_text = _('Transfer to %r') % nick
+
+ self._update()
+
+ def __notify_state_cb(self, file_transfer, pspec):
+ self._update()
+
+ def _update(self):
+ new_state = self.file_transfer.props.state
+ logging.debug('_update state: %r', new_state)
+ if new_state == filetransfer.FT_STATE_PENDING:
+
+ menu_item = MenuItem(_('Cancel'), icon_name='dialog-cancel')
+ menu_item.connect('activate', self.__cancel_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+ vbox.show()
+
+ if self.file_transfer.description:
+ label = gtk.Label(self.file_transfer.description)
+ vbox.add(label)
+ label.show()
+
+ mime_type = self.file_transfer.mime_type
+ type_description = mime.get_mime_description(mime_type)
+
+ size = self._format_size(self.file_transfer.file_size)
+ label = gtk.Label(_('%s (%s)') % (size, type_description))
+ vbox.add(label)
+ label.show()
+
+ elif new_state in [filetransfer.FT_STATE_ACCEPTED,
+ filetransfer.FT_STATE_OPEN]:
+
+ for item in self.menu.get_children():
+ self.menu.remove(item)
+
+ menu_item = MenuItem(_('Cancel'), icon_name='dialog-cancel')
+ menu_item.connect('activate', self.__cancel_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+ vbox.show()
+
+ self.progress_bar = gtk.ProgressBar()
+ vbox.add(self.progress_bar)
+ self.progress_bar.show()
+
+ self.progress_label = gtk.Label('')
+ vbox.add(self.progress_label)
+ self.progress_label.show()
+
+ self.update_progress()
+
+ elif new_state in [filetransfer.FT_STATE_COMPLETED,
+ filetransfer.FT_STATE_CANCELLED]:
+
+ for item in self.menu.get_children():
+ self.menu.remove(item)
+
+ menu_item = MenuItem(_('Dismiss'), icon_name='dialog-cancel')
+ menu_item.connect('activate', self.__dismiss_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ self.update_progress()
+
+ def __cancel_activate_cb(self, menu_item):
+ self.file_transfer.cancel()
+
+ def __dismiss_activate_cb(self, menu_item):
+ self.emit('dismiss-clicked')
diff --git a/shell/src/jarabe/frame/clipboard.py b/shell/src/jarabe/frame/clipboard.py
new file mode 100644
index 0000000..3b9f745
--- /dev/null
+++ b/shell/src/jarabe/frame/clipboard.py
@@ -0,0 +1,149 @@
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import os
+import shutil
+import urlparse
+import tempfile
+
+import gobject
+
+from sugar import mime
+
+from jarabe.frame.clipboardobject import ClipboardObject, Format
+
+class Clipboard(gobject.GObject):
+
+ __gsignals__ = {
+ 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([object])),
+ 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([int])),
+ 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([object]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._objects = {}
+ self._next_id = 0
+
+ def _get_next_object_id(self):
+ self._next_id += 1
+ return self._next_id
+
+ def add_object(self, name):
+ logging.debug('Clipboard.add_object')
+ object_id = self._get_next_object_id()
+ self._objects[object_id] = ClipboardObject(object_id, name)
+ self.emit('object-added', self._objects[object_id])
+ return object_id
+
+ def add_object_format(self, object_id, format_type, data, on_disk):
+ logging.debug('Clipboard.add_object_format')
+ cb_object = self._objects[object_id]
+
+ if format_type == 'XdndDirectSave0':
+ format_ = Format('text/uri-list', data + '\r\n', on_disk)
+ format_.owns_disk_data = True
+ cb_object.add_format(format_)
+ elif on_disk and cb_object.get_percent() == 100:
+ new_uri = self._copy_file(data)
+ cb_object.add_format(Format(format_type, new_uri, on_disk))
+ logging.debug('Added format of type ' + format_type
+ + ' with path at ' + new_uri)
+ else:
+ cb_object.add_format(Format(format_type, data, on_disk))
+ logging.debug('Added in-memory format of type ' + format_type + '.')
+
+ self.emit('object-state-changed', cb_object)
+
+ def delete_object(self, object_id):
+ cb_object = self._objects.pop(object_id)
+ cb_object.destroy()
+ self.emit('object-deleted', object_id)
+ logging.debug('Deleted object with object_id %r', object_id)
+
+ def set_object_percent(self, object_id, percent):
+ cb_object = self._objects[object_id]
+ if percent < 0 or percent > 100:
+ raise ValueError("invalid percentage")
+ if cb_object.get_percent() > percent:
+ raise ValueError("invalid percentage; less than current percent")
+ if cb_object.get_percent() == percent:
+ # ignore setting same percentage
+ return
+
+ cb_object.set_percent(percent)
+
+ if percent == 100:
+ self._process_object(cb_object)
+
+ self.emit('object-state-changed', cb_object)
+
+ def _process_object(self, cb_object):
+ formats = cb_object.get_formats()
+ for format_name, format_ in formats.iteritems():
+ if format_.is_on_disk() and not format_.owns_disk_data:
+ new_uri = self._copy_file(format_.get_data())
+ format_.set_data(new_uri)
+
+ # Add a text/plain format to objects that are text but lack it
+ if 'text/plain' not in formats.keys():
+ if 'UTF8_STRING' in formats.keys():
+ self.add_object_format(
+ cb_object.get_id(), 'text/plain',
+ data=formats['UTF8_STRING'].get_data(), on_disk=False)
+ elif 'text/unicode' in formats.keys():
+ self.add_object_format(
+ cb_object.get_id(), 'text/plain',
+ data=formats['UTF8_STRING'].get_data(), on_disk=False)
+
+ def get_object(self, object_id):
+ logging.debug('Clipboard.get_object')
+ return self._objects[object_id]
+
+ def get_object_data(self, object_id, format_type):
+ logging.debug('Clipboard.get_object_data')
+ cb_object = self._objects[object_id]
+ format_ = cb_object.get_formats()[format_type]
+ return format_
+
+ def _copy_file(self, original_uri):
+ uri = urlparse.urlparse(original_uri)
+ path_, file_name = os.path.split(uri.path)
+
+ root, ext = os.path.splitext(file_name)
+ if not ext or ext == '.':
+ mime_type = mime.get_for_file(uri.path)
+ ext = '.' + mime.get_primary_extension(mime_type)
+
+ f_, new_file_path = tempfile.mkstemp(ext, root)
+ del f_
+ shutil.copyfile(uri.path, new_file_path)
+ os.chmod(new_file_path, 0644)
+
+ return 'file://' + new_file_path
+
+_instance = None
+
+def get_instance():
+ global _instance
+ if not _instance:
+ _instance = Clipboard()
+ return _instance
diff --git a/shell/src/jarabe/frame/clipboardicon.py b/shell/src/jarabe/frame/clipboardicon.py
new file mode 100644
index 0000000..279db08
--- /dev/null
+++ b/shell/src/jarabe/frame/clipboardicon.py
@@ -0,0 +1,158 @@
+# Copyright (C) 2007, Red Hat, Inc.
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import gconf
+
+import gtk
+
+from sugar.graphics.radiotoolbutton import RadioToolButton
+from sugar.graphics.icon import Icon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics import style
+
+from jarabe.frame import clipboard
+from jarabe.frame.clipboardmenu import ClipboardMenu
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+from jarabe.frame.notification import NotificationIcon
+import jarabe.frame
+
+class ClipboardIcon(RadioToolButton):
+ __gtype_name__ = 'SugarClipboardIcon'
+
+ def __init__(self, cb_object, group):
+ RadioToolButton.__init__(self, group=group)
+
+ self.props.palette_invoker = FrameWidgetInvoker(self)
+
+ self._cb_object = cb_object
+ self.owns_clipboard = False
+ self.props.sensitive = False
+ self.props.active = False
+ self._notif_icon = None
+ self._current_percent = None
+
+ self._icon = Icon()
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ self._icon.props.xo_color = color
+ self.set_icon_widget(self._icon)
+ self._icon.show()
+
+ cb_service = clipboard.get_instance()
+ cb_service.connect('object-state-changed',
+ self._object_state_changed_cb)
+
+ child = self.get_child()
+ child.connect('drag_data_get', self._drag_data_get_cb)
+ self.connect('notify::active', self._notify_active_cb)
+
+ def create_palette(self):
+ palette = ClipboardMenu(self._cb_object)
+ palette.set_group_id('frame')
+ return palette
+
+ def get_object_id(self):
+ return self._cb_object.get_id()
+
+ def _drag_data_get_cb(self, widget, context, selection, target_type,
+ event_time):
+ logging.debug('_drag_data_get_cb: requested target ' + selection.target)
+ data = self._cb_object.get_formats()[selection.target].get_data()
+ selection.set(selection.target, 8, data)
+
+ def _put_in_clipboard(self):
+ logging.debug('ClipboardIcon._put_in_clipboard')
+
+ if self._cb_object.get_percent() < 100:
+ raise ValueError('Object is not complete,' \
+ ' cannot be put into the clipboard.')
+
+ targets = self._get_targets()
+ if targets:
+ x_clipboard = gtk.Clipboard()
+ if not x_clipboard.set_with_data(targets,
+ self._clipboard_data_get_cb,
+ self._clipboard_clear_cb,
+ targets):
+ logging.error('GtkClipboard.set_with_data failed!')
+ else:
+ self.owns_clipboard = True
+
+ def _clipboard_data_get_cb(self, x_clipboard, selection, info, targets):
+ if not selection.target in [target[0] for target in targets]:
+ logging.warning('ClipboardIcon._clipboard_data_get_cb: asked %s' \
+ ' but only have %r.', selection.target, targets)
+ return
+ data = self._cb_object.get_formats()[selection.target].get_data()
+ selection.set(selection.target, 8, data)
+
+ def _clipboard_clear_cb(self, x_clipboard, targets):
+ logging.debug('ClipboardIcon._clipboard_clear_cb')
+ self.owns_clipboard = False
+
+ def _object_state_changed_cb(self, cb_service, cb_object):
+ if cb_object != self._cb_object:
+ return
+
+ if cb_object.get_icon():
+ self._icon.props.icon_name = cb_object.get_icon()
+ else:
+ self._icon.props.icon_name = 'application-octet-stream'
+
+ child = self.get_child()
+ child.connect('drag-begin', self._drag_begin_cb)
+ child.drag_source_set(gtk.gdk.BUTTON1_MASK,
+ self._get_targets(),
+ gtk.gdk.ACTION_COPY)
+
+ if cb_object.get_percent() == 100:
+ self.props.sensitive = True
+
+ # Clipboard object became complete. Make it the active one.
+ if self._current_percent < 100 and cb_object.get_percent() == 100:
+ self.props.active = True
+
+ self._notif_icon = NotificationIcon()
+ self._notif_icon.props.icon_name = self._icon.props.icon_name
+ self._notif_icon.props.xo_color = \
+ XoColor('%s,%s' % (self._icon.props.stroke_color,
+ self._icon.props.fill_color))
+ frame = jarabe.frame.get_view()
+ frame.add_notification(self._notif_icon,
+ gtk.CORNER_BOTTOM_LEFT)
+ self._current_percent = cb_object.get_percent()
+
+ def _drag_begin_cb(self, widget, context):
+ # TODO: We should get the pixbuf from the icon, with colors, etc.
+ icon_theme = gtk.icon_theme_get_default()
+ pixbuf = icon_theme.load_icon(self._icon.props.icon_name,
+ style.STANDARD_ICON_SIZE, 0)
+ context.set_icon_pixbuf(pixbuf, hot_x=pixbuf.props.width / 2,
+ hot_y=pixbuf.props.height / 2)
+
+ def _notify_active_cb(self, widget, pspec):
+ if self.props.active:
+ self._put_in_clipboard()
+ else:
+ self.owns_clipboard = False
+
+ def _get_targets(self):
+ targets = []
+ for format_type in self._cb_object.get_formats().keys():
+ targets.append((format_type, 0, 0))
+ return targets
diff --git a/shell/src/jarabe/frame/clipboardmenu.py b/shell/src/jarabe/frame/clipboardmenu.py
new file mode 100644
index 0000000..b998110
--- /dev/null
+++ b/shell/src/jarabe/frame/clipboardmenu.py
@@ -0,0 +1,249 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import tempfile
+import urlparse
+import os
+import logging
+import gconf
+
+import gtk
+
+from sugar.graphics.palette import Palette
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.icon import Icon
+from sugar.graphics.xocolor import XoColor
+from sugar.datastore import datastore
+from sugar import mime
+from sugar import env
+
+from jarabe.frame import clipboard
+from jarabe.journal import misc
+from jarabe.model import bundleregistry
+
+class ClipboardMenu(Palette):
+
+ def __init__(self, cb_object):
+ Palette.__init__(self, text_maxlen=100)
+
+ self._cb_object = cb_object
+
+ self.set_group_id('frame')
+
+ cb_service = clipboard.get_instance()
+ cb_service.connect('object-state-changed',
+ self._object_state_changed_cb)
+
+ self._progress_bar = None
+
+ self._remove_item = MenuItem(_('Remove'), 'list-remove')
+ self._remove_item.connect('activate', self._remove_item_activate_cb)
+ self.menu.append(self._remove_item)
+ self._remove_item.show()
+
+ self._open_item = MenuItem(_('Open'), 'zoom-activity')
+ self._open_item.connect('activate', self._open_item_activate_cb)
+ self.menu.append(self._open_item)
+ self._open_item.show()
+
+ self._journal_item = MenuItem(_('Keep'))
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ icon = Icon(icon_name='document-save', icon_size=gtk.ICON_SIZE_MENU,
+ xo_color=color)
+ self._journal_item.set_image(icon)
+
+ self._journal_item.connect('activate', self._journal_item_activate_cb)
+ self.menu.append(self._journal_item)
+ self._journal_item.show()
+
+ self._update()
+
+ def _update_open_submenu(self):
+ activities = self._get_activities()
+ logging.debug('_update_open_submenu: %r', activities)
+ child = self._open_item.get_child()
+ if activities is None or len(activities) <= 1:
+ child.set_text(_('Open'))
+ if self._open_item.get_submenu() is not None:
+ self._open_item.remove_submenu()
+ return
+
+ child.set_text(_('Open with'))
+ submenu = self._open_item.get_submenu()
+ if submenu is None:
+ submenu = gtk.Menu()
+ self._open_item.set_submenu(submenu)
+ submenu.show()
+ else:
+ for item in submenu.get_children():
+ submenu.remove(item)
+
+ for service_name in activities:
+ registry = bundleregistry.get_registry()
+ activity_info = registry.get_bundle(service_name)
+
+ if not activity_info:
+ logging.warning('Activity %s is unknown.', service_name)
+
+ item = gtk.MenuItem(activity_info.get_name())
+ item.connect('activate', self._open_submenu_item_activate_cb,
+ service_name)
+ submenu.append(item)
+ item.show()
+
+ def _update_items_visibility(self):
+ activities = self._get_activities()
+ installable = self._cb_object.is_bundle()
+ percent = self._cb_object.get_percent()
+
+ if percent == 100 and (activities or installable):
+ self._remove_item.props.sensitive = True
+ self._open_item.props.sensitive = True
+ self._journal_item.props.sensitive = True
+ elif percent == 100 and (not activities and not installable):
+ self._remove_item.props.sensitive = True
+ self._open_item.props.sensitive = False
+ self._journal_item.props.sensitive = True
+ else:
+ self._remove_item.props.sensitive = True
+ self._open_item.props.sensitive = False
+ self._journal_item.props.sensitive = False
+
+ self._update_progress_bar()
+
+ def _get_activities(self):
+ mime_type = self._cb_object.get_mime_type()
+ if not mime_type:
+ return ''
+
+ registry = bundleregistry.get_registry()
+ activities = registry.get_activities_for_type(mime_type)
+ if activities:
+ return [info.get_bundle_id() for info in activities]
+ else:
+ return ''
+
+ def _update_progress_bar(self):
+ percent = self._cb_object.get_percent()
+ if percent == 100.0:
+ if self._progress_bar:
+ self._progress_bar = None
+ self.set_content(None)
+ else:
+ if self._progress_bar is None:
+ self._progress_bar = gtk.ProgressBar()
+ self._progress_bar.show()
+ self.set_content(self._progress_bar)
+
+ self._progress_bar.props.fraction = percent / 100.0
+ self._progress_bar.props.text = '%.2f %%' % percent
+
+ def _object_state_changed_cb(self, cb_service, cb_object):
+ if cb_object != self._cb_object:
+ return
+ self._update()
+
+ def _update(self):
+ self.props.primary_text = self._cb_object.get_name()
+ preview = self._cb_object.get_preview()
+ if preview:
+ self.props.secondary_text = preview
+ self._update_progress_bar()
+ self._update_items_visibility()
+ self._update_open_submenu()
+
+ def _open_item_activate_cb(self, menu_item):
+ logging.debug('_open_item_activate_cb')
+ percent = self._cb_object.get_percent()
+ if percent < 100 or menu_item.get_submenu() is not None:
+ return
+ jobject = self._copy_to_journal()
+ misc.resume(jobject.metadata, self._get_activities()[0])
+ jobject.destroy()
+
+ def _open_submenu_item_activate_cb(self, menu_item, service_name):
+ logging.debug('_open_submenu_item_activate_cb')
+ percent = self._cb_object.get_percent()
+ if percent < 100:
+ return
+ jobject = self._copy_to_journal()
+ misc.resume(jobject.metadata, service_name)
+ jobject.destroy()
+
+ def _remove_item_activate_cb(self, menu_item):
+ cb_service = clipboard.get_instance()
+ cb_service.delete_object(self._cb_object.get_id())
+
+ def _journal_item_activate_cb(self, menu_item):
+ logging.debug('_journal_item_activate_cb')
+ jobject = self._copy_to_journal()
+ jobject.destroy()
+
+ def _write_to_temp_file(self, data):
+ tmp_dir = os.path.join(env.get_profile_path(), 'data')
+ f, file_path = tempfile.mkstemp(dir=tmp_dir)
+ try:
+ os.write(f, data)
+ finally:
+ os.close(f)
+ return file_path
+
+ def _copy_to_journal(self):
+ formats = self._cb_object.get_formats().keys()
+ most_significant_mime_type = mime.choose_most_significant(formats)
+ format_ = self._cb_object.get_formats()[most_significant_mime_type]
+
+ transfer_ownership = False
+ if most_significant_mime_type == 'text/uri-list':
+ uris = mime.split_uri_list(format_.get_data())
+ if len(uris) == 1 and uris[0].startswith('file://'):
+ file_path = urlparse.urlparse(uris[0]).path
+ transfer_ownership = False
+ mime_type = mime.get_for_file(file_path)
+ else:
+ file_path = self._write_to_temp_file(format_.get_data())
+ transfer_ownership = True
+ mime_type = 'text/uri-list'
+ else:
+ if format_.is_on_disk():
+ file_path = urlparse.urlparse(format_.get_data()).path
+ transfer_ownership = False
+ mime_type = mime.get_for_file(file_path)
+ else:
+ file_path = self._write_to_temp_file(format_.get_data())
+ transfer_ownership = True
+ sniffed_mime_type = mime.get_for_file(file_path)
+ if sniffed_mime_type == 'application/octet-stream':
+ mime_type = most_significant_mime_type
+ else:
+ mime_type = sniffed_mime_type
+
+ jobject = datastore.create()
+ jobject.metadata['title'] = self._cb_object.get_name()
+ jobject.metadata['keep'] = '0'
+ jobject.metadata['buddies'] = ''
+ jobject.metadata['preview'] = ''
+ client = gconf.client_get_default()
+ color = client.get_string('/desktop/sugar/user/color')
+ jobject.metadata['icon-color'] = color
+ jobject.metadata['mime_type'] = mime_type
+ jobject.file_path = file_path
+
+ datastore.write(jobject, transfer_ownership=transfer_ownership)
+
+ return jobject
diff --git a/shell/src/jarabe/frame/clipboardobject.py b/shell/src/jarabe/frame/clipboardobject.py
new file mode 100644
index 0000000..e9403f9
--- /dev/null
+++ b/shell/src/jarabe/frame/clipboardobject.py
@@ -0,0 +1,142 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+import urlparse
+import gio
+import gtk
+
+from gettext import gettext as _
+from sugar import mime
+from sugar.bundle.activitybundle import ActivityBundle
+
+class ClipboardObject(object):
+
+ def __init__(self, object_path, name):
+ self._id = object_path
+ self._name = name
+ self._percent = 0
+ self._formats = {}
+
+ def destroy(self):
+ for format_ in self._formats.itervalues():
+ format_.destroy()
+
+ def get_id(self):
+ return self._id
+
+ def get_name(self):
+ name = self._name
+ if not name:
+ mime_type = mime.get_mime_description(self.get_mime_type())
+
+ if not mime_type:
+ mime_type = 'Data'
+ name = _('%s clipping') % mime_type
+
+ return name
+
+ def get_icon(self):
+ mime_type = self.get_mime_type()
+
+ generic_types = mime.get_all_generic_types()
+ for generic_type in generic_types:
+ if mime_type in generic_type.mime_types:
+ return generic_type.icon
+
+ icons = gio.content_type_get_icon(mime_type)
+ icon_name = None
+ if icons is not None:
+ icon_theme = gtk.icon_theme_get_default()
+ for icon_name in icons.props.names:
+ icon_info = icon_theme.lookup_icon(icon_name,
+ gtk.ICON_SIZE_LARGE_TOOLBAR, 0)
+ if icon_info is not None:
+ icon_info.free()
+ return icon_name
+
+ return 'application-octet-stream'
+
+ def get_preview(self):
+ for mime_type in ['text/plain']:
+ if mime_type in self._formats:
+ return self._formats[mime_type].get_data()
+ return ''
+
+ def is_bundle(self):
+ # A bundle will have only one format.
+ if not self._formats:
+ return False
+ else:
+ return self._formats.keys()[0] in [ActivityBundle.MIME_TYPE,
+ ActivityBundle.DEPRECATED_MIME_TYPE]
+
+ def get_percent(self):
+ return self._percent
+
+ def set_percent(self, percent):
+ self._percent = percent
+
+ def add_format(self, format_):
+ self._formats[format_.get_type()] = format_
+
+ def get_formats(self):
+ return self._formats
+
+ def get_mime_type(self):
+ if not self._formats:
+ return ''
+
+ format_ = mime.choose_most_significant(self._formats.keys())
+ if format_ == 'text/uri-list':
+ data = self._formats['text/uri-list'].get_data()
+ uri = urlparse.urlparse(mime.split_uri_list(data)[0], 'file')
+ if uri.scheme == 'file':
+ if os.path.exists(uri.path):
+ format_ = mime.get_for_file(uri.path)
+ else:
+ format_ = mime.get_from_file_name(uri.path)
+ logging.debug('Chose %r!', format_)
+
+ return format_
+
+class Format(object):
+
+ def __init__(self, mime_type, data, on_disk):
+ self.owns_disk_data = False
+
+ self._type = mime_type
+ self._data = data
+ self._on_disk = on_disk
+
+ def destroy(self):
+ if self._on_disk:
+ uri = urlparse.urlparse(self._data)
+ if os.path.isfile(uri.path):
+ os.remove(uri.path)
+
+ def get_type(self):
+ return self._type
+
+ def get_data(self):
+ return self._data
+
+ def set_data(self, data):
+ self._data = data
+
+ def is_on_disk(self):
+ return self._on_disk
diff --git a/shell/src/jarabe/frame/clipboardpanelwindow.py b/shell/src/jarabe/frame/clipboardpanelwindow.py
new file mode 100644
index 0000000..ac324f4
--- /dev/null
+++ b/shell/src/jarabe/frame/clipboardpanelwindow.py
@@ -0,0 +1,103 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from urlparse import urlparse
+
+import gtk
+import hippo
+
+from jarabe.frame.framewindow import FrameWindow
+from jarabe.frame.clipboardtray import ClipboardTray
+
+from jarabe.frame import clipboard
+
+class ClipboardPanelWindow(FrameWindow):
+ def __init__(self, frame, orientation):
+ FrameWindow.__init__(self, orientation)
+
+ self._frame = frame
+
+ # Listening for new clipboard objects
+ # NOTE: we need to keep a reference to gtk.Clipboard in order to keep
+ # listening to it.
+ self._clipboard = gtk.Clipboard()
+ self._clipboard.connect("owner-change", self._owner_change_cb)
+
+ self._clipboard_tray = ClipboardTray()
+ canvas_widget = hippo.CanvasWidget(widget=self._clipboard_tray)
+ self.append(canvas_widget, hippo.PACK_EXPAND)
+
+ # Receiving dnd drops
+ self.drag_dest_set(0, [], 0)
+ self.connect("drag_motion", self._clipboard_tray.drag_motion_cb)
+ self.connect("drag_leave", self._clipboard_tray.drag_leave_cb)
+ self.connect("drag_drop", self._clipboard_tray.drag_drop_cb)
+ self.connect("drag_data_received",
+ self._clipboard_tray.drag_data_received_cb)
+
+ def _owner_change_cb(self, x_clipboard, event):
+ logging.debug("owner_change_cb")
+
+ if self._clipboard_tray.owns_clipboard():
+ return
+
+ cb_service = clipboard.get_instance()
+ key = cb_service.add_object(name="")
+ cb_service.set_object_percent(key, percent=0)
+
+ targets = x_clipboard.wait_for_targets()
+ for target in targets:
+ if target not in ('TIMESTAMP', 'TARGETS',
+ 'MULTIPLE', 'SAVE_TARGETS'):
+ logging.debug('Asking for target %s.', target)
+ selection = x_clipboard.wait_for_contents(target)
+ if not selection:
+ logging.warning('no data for selection target %s.', target)
+ continue
+ self._add_selection(key, selection)
+
+ cb_service.set_object_percent(key, percent=100)
+
+ def _add_selection(self, key, selection):
+ if not selection.data:
+ logging.warning('no data for selection target %s.', selection.type)
+ return
+
+ logging.debug('adding type ' + selection.type + '.')
+
+ cb_service = clipboard.get_instance()
+ if selection.type == 'text/uri-list':
+ uris = selection.get_uris()
+
+ if len(uris) > 1:
+ raise NotImplementedError('Multiple uris in text/uri-list' \
+ ' still not supported.')
+ uri = uris[0]
+ scheme, netloc_, path_, parameters_, query_, fragment_ = \
+ urlparse(uri)
+ on_disk = (scheme == 'file')
+
+ cb_service.add_object_format(key,
+ selection.type,
+ uri,
+ on_disk)
+ else:
+ cb_service.add_object_format(key,
+ selection.type,
+ selection.data,
+ on_disk=False)
+
diff --git a/shell/src/jarabe/frame/clipboardtray.py b/shell/src/jarabe/frame/clipboardtray.py
new file mode 100644
index 0000000..8beb6a8
--- /dev/null
+++ b/shell/src/jarabe/frame/clipboardtray.py
@@ -0,0 +1,216 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+import tempfile
+
+import gtk
+
+from sugar import util
+from sugar.graphics import tray
+from sugar.graphics import style
+
+from jarabe.frame import clipboard
+from jarabe.frame.clipboardicon import ClipboardIcon
+
+class _ContextMap(object):
+ """Maps a drag context to the clipboard object involved in the dragging."""
+ def __init__(self):
+ self._context_map = {}
+
+ def add_context(self, context, object_id, data_types):
+ """Establishes the mapping. data_types will serve us for reference-
+ counting this mapping.
+ """
+ self._context_map[context] = [object_id, data_types]
+
+ def get_object_id(self, context):
+ """Retrieves the object_id associated with context.
+ Will release the association when this function was called as many times
+ as the number of data_types that this clipboard object contains.
+ """
+ [object_id, data_types_left] = self._context_map[context]
+
+ data_types_left = data_types_left - 1
+ if data_types_left == 0:
+ del self._context_map[context]
+ else:
+ self._context_map[context] = [object_id, data_types_left]
+
+ return object_id
+
+ def has_context(self, context):
+ return context in self._context_map
+
+class ClipboardTray(tray.VTray):
+
+ MAX_ITEMS = gtk.gdk.screen_height() / style.GRID_CELL_SIZE - 2
+
+ def __init__(self):
+ tray.VTray.__init__(self, align=tray.ALIGN_TO_END)
+ self._icons = {}
+ self._context_map = _ContextMap()
+
+ cb_service = clipboard.get_instance()
+ cb_service.connect('object-added', self._object_added_cb)
+ cb_service.connect('object-deleted', self._object_deleted_cb)
+
+ def owns_clipboard(self):
+ for icon in self._icons.values():
+ if icon.owns_clipboard:
+ return True
+ return False
+
+ def _add_selection(self, object_id, selection):
+ if not selection.data:
+ return
+
+ logging.debug('ClipboardTray: adding type %r', selection.type)
+
+ cb_service = clipboard.get_instance()
+ if selection.type == 'text/uri-list':
+ uris = selection.data.split('\n')
+ if len(uris) > 1:
+ raise NotImplementedError('Multiple uris in text/uri-list' \
+ ' still not supported.')
+
+ cb_service.add_object_format(object_id,
+ selection.type,
+ uris[0],
+ on_disk=True)
+ else:
+ cb_service.add_object_format(object_id,
+ selection.type,
+ selection.data,
+ on_disk=False)
+
+ def _object_added_cb(self, cb_service, cb_object):
+ if self._icons:
+ group = self._icons.values()[0]
+ else:
+ group = None
+
+ icon = ClipboardIcon(cb_object, group)
+ self.add_item(icon)
+ icon.show()
+ self._icons[cb_object.get_id()] = icon
+
+ objects_to_delete = self.get_children()[:-self.MAX_ITEMS]
+ for icon in objects_to_delete:
+ logging.debug('ClipboardTray: deleting surplus object')
+ cb_service = clipboard.get_instance()
+ cb_service.delete_object(icon.get_object_id())
+
+ logging.debug('ClipboardTray: %r was added', cb_object.get_id())
+
+ def _object_deleted_cb(self, cb_service, object_id):
+ icon = self._icons[object_id]
+ self.remove_item(icon)
+ del self._icons[object_id]
+ logging.debug('ClipboardTray: %r was deleted', object_id)
+
+ def drag_motion_cb(self, widget, context, x, y, time):
+ logging.debug('ClipboardTray._drag_motion_cb')
+
+ if self._internal_drag(context):
+ context.drag_status(gtk.gdk.ACTION_MOVE, time)
+ else:
+ context.drag_status(gtk.gdk.ACTION_COPY, time)
+ self.props.drag_active = True
+
+ return True
+
+ def drag_leave_cb(self, widget, context, time):
+ self.props.drag_active = False
+
+ def drag_drop_cb(self, widget, context, x, y, time):
+ logging.debug('ClipboardTray._drag_drop_cb')
+
+ if self._internal_drag(context):
+ # TODO: We should move the object within the clipboard here
+ if not self._context_map.has_context(context):
+ context.drop_finish(False, gtk.get_current_event_time())
+ return False
+
+ cb_service = clipboard.get_instance()
+ object_id = cb_service.add_object(name="")
+
+ self._context_map.add_context(context, object_id, len(context.targets))
+
+ if 'XdndDirectSave0' in context.targets:
+ window = context.source_window
+ prop_type, format_, filename = \
+ window.property_get('XdndDirectSave0','text/plain')
+
+ # FIXME query the clipboard service for a filename?
+ base_dir = tempfile.gettempdir()
+ dest_filename = util.unique_id()
+
+ name_, dot, extension = filename.rpartition('.')
+ dest_filename += dot + extension
+
+ dest_uri = 'file://' + os.path.join(base_dir, dest_filename)
+
+ window.property_change('XdndDirectSave0', prop_type, format_,
+ gtk.gdk.PROP_MODE_REPLACE, dest_uri)
+
+ widget.drag_get_data(context, 'XdndDirectSave0', time)
+ else:
+ for target in context.targets:
+ if str(target) not in ('TIMESTAMP', 'TARGETS', 'MULTIPLE'):
+ widget.drag_get_data(context, target, time)
+
+ cb_service.set_object_percent(object_id, percent=100)
+
+ return True
+
+ def drag_data_received_cb(self, widget, context, x, y, selection,
+ targetType, time):
+ logging.debug('ClipboardTray: got data for target %r',
+ selection.target)
+
+ object_id = self._context_map.get_object_id(context)
+ try:
+ if selection is None:
+ logging.warn('ClipboardTray: empty selection for target %s',
+ selection.target)
+ elif selection.target == 'XdndDirectSave0':
+ if selection.data == 'S':
+ window = context.source_window
+
+ prop_type, format_, dest = \
+ window.property_get('XdndDirectSave0', 'text/plain')
+
+ clipboardservice = clipboard.get_instance()
+ clipboardservice.add_object_format( \
+ object_id, 'XdndDirectSave0', dest, on_disk=True)
+ else:
+ self._add_selection(object_id, selection)
+
+ finally:
+ # If it's the last target to be processed, finish
+ # the dnd transaction
+ if not self._context_map.has_context(context):
+ context.drop_finish(True, gtk.get_current_event_time())
+
+ def _internal_drag(self, context):
+ view_ancestor = context.get_source_widget().get_ancestor(gtk.Viewport)
+ if view_ancestor is self._viewport:
+ return True
+ else:
+ return False
+
diff --git a/shell/src/jarabe/frame/devicestray.py b/shell/src/jarabe/frame/devicestray.py
new file mode 100644
index 0000000..72affe3
--- /dev/null
+++ b/shell/src/jarabe/frame/devicestray.py
@@ -0,0 +1,54 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+import traceback
+import logging
+
+from sugar.graphics import tray
+
+from jarabe import config
+
+class DevicesTray(tray.HTray):
+ def __init__(self):
+ tray.HTray.__init__(self, align=tray.ALIGN_TO_END)
+
+ for f in os.listdir(os.path.join(config.ext_path, 'deviceicon')):
+ if f.endswith('.py') and not f.startswith('__'):
+ module_name = f[:-3]
+ try:
+ mod = __import__('deviceicon.' + module_name, globals(),
+ locals(), [module_name])
+ mod.setup(self)
+ except Exception:
+ logging.error('Exception while loading extension:\n' + \
+ ''.join(traceback.format_exception(*sys.exc_info())))
+
+ def add_device(self, view):
+ index = 0
+ relative_index = getattr(view, "FRAME_POSITION_RELATIVE", -1)
+ for item in self.get_children():
+ current_relative_index = getattr(item, "FRAME_POSITION_RELATIVE", 0)
+ if current_relative_index >= relative_index:
+ index += 1
+ else:
+ break
+ self.add_item(view, index=index)
+ view.show()
+
+ def remove_device(self, view):
+ self.remove_item(view)
diff --git a/shell/src/jarabe/frame/eventarea.py b/shell/src/jarabe/frame/eventarea.py
new file mode 100644
index 0000000..166aaf5
--- /dev/null
+++ b/shell/src/jarabe/frame/eventarea.py
@@ -0,0 +1,151 @@
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gobject
+import wnck
+import gconf
+
+_MAX_DELAY = 1000
+
+class EventArea(gobject.GObject):
+ __gsignals__ = {
+ 'enter': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ 'leave': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._windows = []
+ self._hover = False
+ self._sids = {}
+ client = gconf.client_get_default()
+ self._edge_delay = client.get_int('/desktop/sugar/frame/edge_delay')
+ self._corner_delay = client.get_int('/desktop/sugar/frame/corner_delay')
+
+ right = gtk.gdk.screen_width() - 1
+ bottom = gtk.gdk.screen_height() -1
+ width = gtk.gdk.screen_width() - 2
+ height = gtk.gdk.screen_height() - 2
+
+ if self._edge_delay != _MAX_DELAY:
+ invisible = self._create_invisible(1, 0, width, 1,
+ self._edge_delay)
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(1, bottom, width, 1,
+ self._edge_delay)
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(0, 1, 1, height,
+ self._edge_delay)
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(right, 1, 1, height,
+ self._edge_delay)
+ self._windows.append(invisible)
+
+ if self._corner_delay != _MAX_DELAY:
+ invisible = self._create_invisible(0, 0, 1, 1,
+ self._corner_delay)
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(right, 0, 1, 1,
+ self._corner_delay)
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(0, bottom, 1, 1,
+ self._corner_delay)
+ self._windows.append(invisible)
+
+ invisible = self._create_invisible(right, bottom, 1, 1,
+ self._corner_delay)
+ self._windows.append(invisible)
+
+ screen = wnck.screen_get_default()
+ screen.connect('window-stacking-changed',
+ self._window_stacking_changed_cb)
+
+ def _create_invisible(self, x, y, width, height, delay):
+ invisible = gtk.Invisible()
+ if delay >= 0:
+ invisible.connect('enter-notify-event', self._enter_notify_cb,
+ delay)
+ invisible.connect('leave-notify-event', self._leave_notify_cb)
+
+ invisible.drag_dest_set(0, [], 0)
+ invisible.connect('drag_motion', self._drag_motion_cb)
+ invisible.connect('drag_leave', self._drag_leave_cb)
+
+ invisible.realize()
+ invisible.window.set_events(gtk.gdk.POINTER_MOTION_MASK |
+ gtk.gdk.ENTER_NOTIFY_MASK |
+ gtk.gdk.LEAVE_NOTIFY_MASK)
+ invisible.window.move_resize(x, y, width, height)
+
+ return invisible
+
+ def _notify_enter(self):
+ if not self._hover:
+ self._hover = True
+ self.emit('enter')
+
+ def _notify_leave(self):
+ if self._hover:
+ self._hover = False
+ self.emit('leave')
+
+ def _enter_notify_cb(self, widget, event, delay):
+ if widget in self._sids:
+ gobject.source_remove(self._sids[widget])
+ self._sids[widget] = gobject.timeout_add(delay,
+ self.__delay_cb,
+ widget)
+
+ def __delay_cb(self, widget):
+ del self._sids[widget]
+ self._notify_enter()
+ return False
+
+ def _leave_notify_cb(self, widget, event):
+ if widget in self._sids:
+ gobject.source_remove(self._sids[widget])
+ del self._sids[widget]
+ self._notify_leave()
+
+ def _drag_motion_cb(self, widget, drag_context, x, y, timestamp):
+ drag_context.drag_status(0, timestamp)
+ self._notify_enter()
+ return True
+
+ def _drag_leave_cb(self, widget, drag_context, timestamp):
+ self._notify_leave()
+ return True
+
+ def show(self):
+ for window in self._windows:
+ window.show()
+
+ def hide(self):
+ for window in self._windows:
+ window.hide()
+
+ def _window_stacking_changed_cb(self, screen):
+ for window in self._windows:
+ window.window.raise_()
diff --git a/shell/src/jarabe/frame/frame.py b/shell/src/jarabe/frame/frame.py
new file mode 100644
index 0000000..7dde55b
--- /dev/null
+++ b/shell/src/jarabe/frame/frame.py
@@ -0,0 +1,351 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import gtk
+import gobject
+import hippo
+
+from sugar.graphics import animator
+from sugar.graphics import style
+from sugar.graphics import palettegroup
+from sugar import profile
+
+from jarabe.frame.eventarea import EventArea
+from jarabe.frame.activitiestray import ActivitiesTray
+from jarabe.frame.zoomtoolbar import ZoomToolbar
+from jarabe.frame.friendstray import FriendsTray
+from jarabe.frame.devicestray import DevicesTray
+from jarabe.frame.framewindow import FrameWindow
+from jarabe.frame.clipboardpanelwindow import ClipboardPanelWindow
+from jarabe.frame.notification import NotificationIcon, NotificationWindow
+from jarabe.model import notifications
+
+TOP_RIGHT = 0
+TOP_LEFT = 1
+BOTTOM_RIGHT = 2
+BOTTOM_LEFT = 3
+
+_FRAME_HIDING_DELAY = 500
+_NOTIFICATION_DURATION = 5000
+
+class _Animation(animator.Animation):
+ def __init__(self, frame, end):
+ start = frame.current_position
+ animator.Animation.__init__(self, start, end)
+ self._frame = frame
+
+ def next_frame(self, current):
+ self._frame.move(current)
+
+class _MouseListener(object):
+ def __init__(self, frame):
+ self._frame = frame
+ self._hide_sid = 0
+
+ def mouse_enter(self):
+ self._show_frame()
+
+ def mouse_leave(self):
+ if self._frame.mode == Frame.MODE_MOUSE:
+ self._hide_frame()
+
+ def _show_frame(self):
+ if self._hide_sid != 0:
+ gobject.source_remove(self._hide_sid)
+ self._frame.show(Frame.MODE_MOUSE)
+
+ def _hide_frame_timeout_cb(self):
+ self._frame.hide()
+ return False
+
+ def _hide_frame(self):
+ if self._hide_sid != 0:
+ gobject.source_remove(self._hide_sid)
+ self._hide_sid = gobject.timeout_add(
+ _FRAME_HIDING_DELAY, self._hide_frame_timeout_cb)
+
+class _KeyListener(object):
+ def __init__(self, frame):
+ self._frame = frame
+
+ def key_press(self):
+ if self._frame.visible:
+ if self._frame.mode == Frame.MODE_KEYBOARD:
+ self._frame.hide()
+ else:
+ self._frame.show(Frame.MODE_KEYBOARD)
+
+class Frame(object):
+ MODE_MOUSE = 0
+ MODE_KEYBOARD = 1
+ MODE_NON_INTERACTIVE = 2
+
+ def __init__(self):
+ logging.debug("STARTUP: Loading the frame")
+ self.mode = None
+
+ self._palette_group = palettegroup.get_group('frame')
+ self._palette_group.connect('popdown', self._palette_group_popdown_cb)
+
+ self._left_panel = None
+ self._right_panel = None
+ self._top_panel = None
+ self._bottom_panel = None
+
+ self.current_position = 0.0
+ self._animator = None
+
+ self._event_area = EventArea()
+ self._event_area.connect('enter', self._enter_corner_cb)
+ self._event_area.show()
+
+ self._top_panel = self._create_top_panel()
+ self._bottom_panel = self._create_bottom_panel()
+ self._left_panel = self._create_left_panel()
+ self._right_panel = self._create_right_panel()
+
+ screen = gtk.gdk.screen_get_default()
+ screen.connect('size-changed', self._size_changed_cb)
+
+ self._key_listener = _KeyListener(self)
+ self._mouse_listener = _MouseListener(self)
+
+ self._notif_by_icon = {}
+
+ notification_service = notifications.get_service()
+ notification_service.notification_received.connect(
+ self.__notification_received_cb)
+ notification_service.notification_cancelled.connect(
+ self.__notification_cancelled_cb)
+
+ def is_visible(self):
+ return self.current_position != 0.0
+
+ visible = property(is_visible, None)
+
+ def hide(self):
+ if self._animator:
+ self._animator.stop()
+
+ self._animator = animator.Animator(0.5)
+ self._animator.add(_Animation(self, 0.0))
+ self._animator.start()
+
+ self.mode = None
+
+ def show(self, mode):
+ if self.visible:
+ return
+ if self._animator:
+ self._animator.stop()
+
+ self.mode = mode
+
+ self._animator = animator.Animator(0.5)
+ self._animator.add(_Animation(self, 1.0))
+ self._animator.start()
+
+ def move(self, pos):
+ self.current_position = pos
+ self._update_position()
+
+ def _is_hover(self):
+ return (self._top_panel.hover or \
+ self._bottom_panel.hover or \
+ self._left_panel.hover or \
+ self._right_panel.hover)
+
+ def _create_top_panel(self):
+ panel = self._create_panel(gtk.POS_TOP)
+
+ # TODO: setting box_width and hippo.PACK_EXPAND looks like a hack to me.
+ # Why hippo isn't respecting the request size of these controls?
+
+ zoom_toolbar = ZoomToolbar()
+ panel.append(hippo.CanvasWidget(widget=zoom_toolbar,
+ box_width=4*style.GRID_CELL_SIZE))
+ zoom_toolbar.show()
+
+ activities_tray = ActivitiesTray()
+ panel.append(hippo.CanvasWidget(widget=activities_tray),
+ hippo.PACK_EXPAND)
+ activities_tray.show()
+
+ return panel
+
+ def _create_bottom_panel(self):
+ panel = self._create_panel(gtk.POS_BOTTOM)
+
+ # TODO: same issue as in _create_top_panel()
+ devices_tray = DevicesTray()
+ panel.append(hippo.CanvasWidget(widget=devices_tray), hippo.PACK_EXPAND)
+ devices_tray.show()
+
+ return panel
+
+ def _create_right_panel(self):
+ panel = self._create_panel(gtk.POS_RIGHT)
+
+ tray = FriendsTray()
+ panel.append(hippo.CanvasWidget(widget=tray), hippo.PACK_EXPAND)
+ tray.show()
+
+ return panel
+
+ def _create_left_panel(self):
+ panel = ClipboardPanelWindow(self, gtk.POS_LEFT)
+
+ self._connect_to_panel(panel)
+ panel.connect('drag-motion', self._drag_motion_cb)
+ panel.connect('drag-leave', self._drag_leave_cb)
+
+ return panel
+
+ def _create_panel(self, orientation):
+ panel = FrameWindow(orientation)
+ self._connect_to_panel(panel)
+
+ return panel
+
+ def _move_panel(self, panel, pos, x1, y1, x2, y2):
+ x = (x2 - x1) * pos + x1
+ y = (y2 - y1) * pos + y1
+
+ panel.move(int(x), int(y))
+
+ # FIXME we should hide and show as necessary to free memory
+ if not panel.props.visible:
+ panel.show()
+
+ def _connect_to_panel(self, panel):
+ panel.connect('enter-notify-event', self._enter_notify_cb)
+ panel.connect('leave-notify-event', self._leave_notify_cb)
+
+ def _update_position(self):
+ screen_h = gtk.gdk.screen_height()
+ screen_w = gtk.gdk.screen_width()
+
+ self._move_panel(self._top_panel, self.current_position,
+ 0, - self._top_panel.size, 0, 0)
+
+ self._move_panel(self._bottom_panel, self.current_position,
+ 0, screen_h, 0, screen_h - self._bottom_panel.size)
+
+ self._move_panel(self._left_panel, self.current_position,
+ - self._left_panel.size, 0, 0, 0)
+
+ self._move_panel(self._right_panel, self.current_position,
+ screen_w, 0, screen_w - self._right_panel.size, 0)
+
+ def _size_changed_cb(self, screen):
+ self._update_position()
+
+ def _enter_notify_cb(self, window, event):
+ if event.detail != gtk.gdk.NOTIFY_INFERIOR:
+ self._mouse_listener.mouse_enter()
+
+ def _leave_notify_cb(self, window, event):
+ if event.detail == gtk.gdk.NOTIFY_INFERIOR:
+ return
+
+ if not self._is_hover() and not self._palette_group.is_up():
+ self._mouse_listener.mouse_leave()
+
+ def _palette_group_popdown_cb(self, group):
+ if not self._is_hover():
+ self._mouse_listener.mouse_leave()
+
+ def _drag_motion_cb(self, window, context, x, y, time):
+ self._mouse_listener.mouse_enter()
+
+ def _drag_leave_cb(self, window, drag_context, timestamp):
+ self._mouse_listener.mouse_leave()
+
+ def _enter_corner_cb(self, event_area):
+ self._mouse_listener.mouse_enter()
+
+ def notify_key_press(self):
+ self._key_listener.key_press()
+
+ def add_notification(self, icon, corner=gtk.CORNER_TOP_LEFT,
+ duration=_NOTIFICATION_DURATION):
+
+ if not isinstance(icon, NotificationIcon):
+ raise TypeError('icon must be a NotificationIcon.')
+
+ window = NotificationWindow()
+
+ screen = gtk.gdk.screen_get_default()
+ if corner == gtk.CORNER_TOP_LEFT:
+ window.move(0, 0)
+ elif corner == gtk.CORNER_TOP_RIGHT:
+ window.move(screen.get_width() - style.GRID_CELL_SIZE, 0)
+ elif corner == gtk.CORNER_BOTTOM_LEFT:
+ window.move(0, screen.get_height() - style.GRID_CELL_SIZE)
+ elif corner == gtk.CORNER_BOTTOM_RIGHT:
+ window.move(screen.get_width() - style.GRID_CELL_SIZE,
+ screen.get_height() - style.GRID_CELL_SIZE)
+ else:
+ raise ValueError('Inalid corner: %r' % corner)
+
+ window.add(icon)
+ icon.show()
+ window.show()
+
+ self._notif_by_icon[icon] = window
+
+ gobject.timeout_add(duration,
+ lambda: self.remove_notification(icon))
+
+ def remove_notification(self, icon):
+ if icon not in self._notif_by_icon:
+ logging.debug('icon %r not in list of notifications.', icon)
+ return
+
+ window = self._notif_by_icon[icon]
+ window.destroy()
+ del self._notif_by_icon[icon]
+
+ def __notification_received_cb(self, **kwargs):
+ logging.debug('__notification_received_cb')
+ icon = NotificationIcon()
+
+ hints = kwargs['hints']
+
+ icon_file_name = hints.get('x-sugar-icon-file-name', '')
+ if icon_file_name:
+ icon.props.icon_filename = icon_file_name
+ else:
+ icon.props.icon_name = 'application-octet-stream'
+
+ icon_colors = hints.get('x-sugar-icon-colors', '')
+ if not icon_colors:
+ icon_colors = profile.get_color()
+ icon.props.xo_color = icon_colors
+
+ duration = kwargs.get('expire_timeout', -1)
+ if duration == -1:
+ duration = _NOTIFICATION_DURATION
+
+ self.add_notification(icon, gtk.CORNER_TOP_RIGHT, duration)
+
+ def __notification_cancelled_cb(self, **kwargs):
+ # Do nothing for now. Our notification UI is so simple, there's no
+ # point yet.
+ pass
+
diff --git a/shell/src/jarabe/frame/frameinvoker.py b/shell/src/jarabe/frame/frameinvoker.py
new file mode 100644
index 0000000..e4a13e1
--- /dev/null
+++ b/shell/src/jarabe/frame/frameinvoker.py
@@ -0,0 +1,36 @@
+# Copyright (C) 2007, Eduardo Silva <edsiper@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+
+from sugar.graphics import style
+from sugar.graphics.palette import WidgetInvoker
+
+def _get_screen_area():
+ frame_thickness = style.GRID_CELL_SIZE
+
+ x = y = frame_thickness
+ width = gtk.gdk.screen_width() - frame_thickness
+ height = gtk.gdk.screen_height() - frame_thickness
+
+ return gtk.gdk.Rectangle(x, y, width, height)
+
+class FrameWidgetInvoker(WidgetInvoker):
+ def __init__(self, widget):
+ WidgetInvoker.__init__(self, widget, widget.child)
+
+ self._position_hint = self.ANCHORED
+ self._screen_area = _get_screen_area()
diff --git a/shell/src/jarabe/frame/framewindow.py b/shell/src/jarabe/frame/framewindow.py
new file mode 100644
index 0000000..a7d8fe7
--- /dev/null
+++ b/shell/src/jarabe/frame/framewindow.py
@@ -0,0 +1,117 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import hippo
+
+from sugar.graphics import style
+
+class FrameWindow(gtk.Window):
+ __gtype_name__ = 'SugarFrameWindow'
+
+ def __init__(self, position):
+ gtk.Window.__init__(self)
+ self.hover = False
+ self.size = style.GRID_CELL_SIZE + style.LINE_WIDTH
+
+ accel_group = gtk.AccelGroup()
+ self.set_data('sugar-accel-group', accel_group)
+ self.add_accel_group(accel_group)
+
+ self._position = position
+
+ self.set_decorated(False)
+ self.connect('realize', self._realize_cb)
+ self.connect('enter-notify-event', self._enter_notify_cb)
+ self.connect('leave-notify-event', self._leave_notify_cb)
+
+ self._canvas = hippo.Canvas()
+ self.add(self._canvas)
+ self._canvas.show()
+
+ box = hippo.CanvasBox()
+ self._canvas.set_root(box)
+
+ bg_box = hippo.CanvasBox(
+ border_color=style.COLOR_BUTTON_GREY.get_int())
+ box.append(bg_box, hippo.PACK_EXPAND)
+
+ self._bg = hippo.CanvasBox()
+ bg_box.append(self._bg, hippo.PACK_EXPAND)
+
+ padding = style.GRID_CELL_SIZE
+ border = style.LINE_WIDTH
+
+ if position == gtk.POS_TOP or position == gtk.POS_BOTTOM:
+ box.props.orientation = hippo.ORIENTATION_HORIZONTAL
+ box.props.padding_left = padding
+ box.props.padding_right = padding
+ box.props.padding_top = 0
+ box.props.padding_bottom = 0
+ self._bg.props.orientation = hippo.ORIENTATION_HORIZONTAL
+ self._bg.props.padding_left = border * 2
+ self._bg.props.padding_right = border * 2
+ else:
+ box.props.orientation = hippo.ORIENTATION_VERTICAL
+ box.props.padding_left = 0
+ box.props.padding_right = 0
+ box.props.padding_top = padding
+ box.props.padding_bottom = padding
+ self._bg.props.orientation = hippo.ORIENTATION_VERTICAL
+ self._bg.props.padding_top = border * 2
+ self._bg.props.padding_bottom = border * 2
+
+ if position == gtk.POS_TOP:
+ bg_box.props.orientation = hippo.ORIENTATION_HORIZONTAL
+ bg_box.props.border_bottom = border
+ elif position == gtk.POS_BOTTOM:
+ bg_box.props.orientation = hippo.ORIENTATION_HORIZONTAL
+ bg_box.props.border_top = border
+ elif position == gtk.POS_LEFT:
+ bg_box.props.orientation = hippo.ORIENTATION_VERTICAL
+ bg_box.props.border_right = border
+ elif position == gtk.POS_RIGHT:
+ bg_box.props.orientation = hippo.ORIENTATION_VERTICAL
+ bg_box.props.border_left = border
+
+ self._update_size()
+
+ screen = gtk.gdk.screen_get_default()
+ screen.connect('size-changed', self._size_changed_cb)
+
+ def append(self, child, flags=0):
+ self._bg.append(child, flags)
+
+ def _update_size(self):
+ if self._position == gtk.POS_TOP or self._position == gtk.POS_BOTTOM:
+ self.resize(gtk.gdk.screen_width(), self.size)
+ else:
+ self.resize(self.size, gtk.gdk.screen_height())
+
+ def _realize_cb(self, widget):
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
+ self.window.set_accept_focus(False)
+
+ def _enter_notify_cb(self, window, event):
+ if event.detail != gtk.gdk.NOTIFY_INFERIOR:
+ self.hover = True
+
+ def _leave_notify_cb(self, window, event):
+ if event.detail != gtk.gdk.NOTIFY_INFERIOR:
+ self.hover = False
+
+ def _size_changed_cb(self, screen):
+ self._update_size()
diff --git a/shell/src/jarabe/frame/friendstray.py b/shell/src/jarabe/frame/friendstray.py
new file mode 100644
index 0000000..141505b
--- /dev/null
+++ b/shell/src/jarabe/frame/friendstray.py
@@ -0,0 +1,118 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+from sugar.graphics.tray import VTray, TrayIcon
+
+from jarabe.view.buddymenu import BuddyMenu
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+from jarabe.model import shell
+from jarabe.model.buddy import get_owner_instance
+from jarabe.model import neighborhood
+
+class FriendIcon(TrayIcon):
+ def __init__(self, buddy):
+ TrayIcon.__init__(self, icon_name='computer-xo',
+ xo_color=buddy.get_color())
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+ self.palette = BuddyMenu(buddy)
+ self.palette.props.icon_visible = False
+ self.palette.set_group_id('frame')
+
+class FriendsTray(VTray):
+ def __init__(self):
+ VTray.__init__(self)
+
+ self._shared_activity = None
+ self._buddies = {}
+
+ shell.get_model().connect('active-activity-changed',
+ self.__active_activity_changed_cb)
+
+ neighborhood.get_model().connect('activity-added',
+ self.__neighborhood_activity_added_cb)
+
+ def add_buddy(self, buddy):
+ if self._buddies.has_key(buddy.props.key):
+ return
+
+ icon = FriendIcon(buddy)
+ self.add_item(icon)
+ icon.show()
+
+ self._buddies[buddy.props.key] = icon
+
+ def remove_buddy(self, buddy):
+ if not self._buddies.has_key(buddy.props.key):
+ return
+
+ self.remove_item(self._buddies[buddy.props.key])
+ del self._buddies[buddy.props.key]
+
+ def clear(self):
+ for item in self.get_children():
+ self.remove_item(item)
+ item.destroy()
+ self._buddies = {}
+
+ def __neighborhood_activity_added_cb(self, neighborhood_model,
+ shared_activity):
+ logging.debug('FriendsTray.__neighborhood_activity_added_cb')
+ self.clear()
+
+ # always display ourselves
+ self.add_buddy(get_owner_instance())
+
+ self._set_current_activity(shared_activity.activity_id)
+
+ def __active_activity_changed_cb(self, home_model, home_activity):
+ logging.debug('FriendsTray.__active_activity_changed_cb')
+ self.clear()
+
+ # always display ourselves
+ self.add_buddy(get_owner_instance())
+
+ if home_activity is None:
+ return
+
+ activity_id = home_activity.get_activity_id()
+ if activity_id is None:
+ return
+
+ self._set_current_activity(activity_id)
+
+ def _set_current_activity(self, activity_id):
+ logging.debug('FriendsTray._set_current_activity')
+ neighborhood_model = neighborhood.get_model()
+ self._shared_activity = neighborhood_model.get_activity(activity_id)
+ if self._shared_activity is None:
+ return
+
+ for buddy in self._shared_activity.get_buddies():
+ self.add_buddy(buddy)
+
+ self._shared_activity.connect('buddy-added', self.__buddy_added_cb)
+ self._shared_activity.connect('buddy-removed', self.__buddy_removed_cb)
+
+ def __buddy_added_cb(self, activity, buddy):
+ logging.debug('FriendsTray.__buddy_added_cb')
+ self.add_buddy(buddy)
+
+ def __buddy_removed_cb(self, activity, buddy):
+ logging.debug('FriendsTray.__buddy_removed_cb')
+ self.remove_buddy(buddy)
diff --git a/shell/src/jarabe/frame/notification.py b/shell/src/jarabe/frame/notification.py
new file mode 100644
index 0000000..83dc27e
--- /dev/null
+++ b/shell/src/jarabe/frame/notification.py
@@ -0,0 +1,100 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gobject
+import gtk
+
+from sugar.graphics import style
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.view.pulsingicon import PulsingIcon
+
+class NotificationIcon(gtk.EventBox):
+ __gtype_name__ = 'SugarNotificationIcon'
+
+ __gproperties__ = {
+ 'xo-color' : (object, None, None, gobject.PARAM_READWRITE),
+ 'icon-name' : (str, None, None, None, gobject.PARAM_READWRITE),
+ 'icon-filename' : (str, None, None, None, gobject.PARAM_READWRITE)
+ }
+
+ _PULSE_TIMEOUT = 3
+
+ def __init__(self, **kwargs):
+ self._icon = PulsingIcon(pixel_size=style.STANDARD_ICON_SIZE)
+ gobject.GObject.__init__(self, **kwargs)
+ self.props.visible_window = False
+
+ self._icon.props.pulse_color = \
+ XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self._icon.props.pulsing = True
+ self.add(self._icon)
+ self._icon.show()
+
+ gobject.timeout_add_seconds(self._PULSE_TIMEOUT, self.__stop_pulsing_cb)
+
+ self.set_size_request(style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
+
+ def __stop_pulsing_cb(self):
+ self._icon.props.pulsing = False
+ return False
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'xo-color':
+ if self._icon.props.base_color != value:
+ self._icon.props.base_color = value
+ elif pspec.name == 'icon-name':
+ if self._icon.props.icon_name != value:
+ self._icon.props.icon_name = value
+ elif pspec.name == 'icon-filename':
+ if self._icon.props.file != value:
+ self._icon.props.file = value
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'xo-color':
+ return self._icon.props.base_color
+ elif pspec.name == 'icon-name':
+ return self._icon.props.icon_name
+ elif pspec.name == 'icon-filename':
+ return self._icon.props.file
+
+ def _set_palette(self, palette):
+ self._icon.palette = palette
+
+ def _get_palette(self):
+ return self._icon.palette
+
+ palette = property(_get_palette, _set_palette)
+
+class NotificationWindow(gtk.Window):
+ __gtype_name__ = 'SugarNotificationWindow'
+
+ def __init__(self, **kwargs):
+
+ gtk.Window.__init__(self, **kwargs)
+
+ self.set_decorated(False)
+ self.set_resizable(False)
+ self.connect('realize', self._realize_cb)
+
+ def _realize_cb(self, widget):
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.window.set_accept_focus(False)
+
+ color = gtk.gdk.color_parse(style.COLOR_TOOLBAR_GREY.get_html())
+ self.modify_bg(gtk.STATE_NORMAL, color)
+
diff --git a/shell/src/jarabe/frame/zoomtoolbar.py b/shell/src/jarabe/frame/zoomtoolbar.py
new file mode 100644
index 0000000..2ed3c54
--- /dev/null
+++ b/shell/src/jarabe/frame/zoomtoolbar.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2009 Simon Schampijer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+
+import gtk
+
+from sugar.graphics.palette import Palette
+from sugar.graphics.radiotoolbutton import RadioToolButton
+
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+from jarabe.model import shell
+
+class ZoomToolbar(gtk.Toolbar):
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ # we shouldn't be mirrored in RTL locales
+ self.set_direction(gtk.TEXT_DIR_LTR)
+
+ self._mesh_button = self._add_button('zoom-neighborhood',
+ _('Neighborhood'), _('F1'), shell.ShellModel.ZOOM_MESH)
+ self._groups_button = self._add_button('zoom-groups',
+ _('Group'), _('F2'), shell.ShellModel.ZOOM_GROUP)
+ self._home_button = self._add_button('zoom-home',
+ _('Home'), _('F3'), shell.ShellModel.ZOOM_HOME)
+ self._activity_button = self._add_button('zoom-activity',
+ _('Activity'), _('F4'), shell.ShellModel.ZOOM_ACTIVITY)
+
+ shell_model = shell.get_model()
+ self._set_zoom_level(shell_model.zoom_level)
+ shell_model.zoom_level_changed.connect(self.__zoom_level_changed_cb)
+
+ def _add_button(self, icon_name, label, accelerator, zoom_level):
+ if self.get_children():
+ group = self.get_children()[0]
+ else:
+ group = None
+
+ button = RadioToolButton(named_icon=icon_name, group=group,
+ accelerator=accelerator)
+ button.connect('clicked', self.__level_clicked_cb, zoom_level)
+ self.add(button)
+ button.show()
+
+ palette = Palette(label)
+ palette.props.invoker = FrameWidgetInvoker(button)
+ palette.set_group_id('frame')
+ button.set_palette(palette)
+
+ return button
+
+ def __level_clicked_cb(self, button, level):
+ if not button.get_active():
+ return
+
+ shell.get_model().set_zoom_level(level)
+
+ def __zoom_level_changed_cb(self, **kwargs):
+ self._set_zoom_level(kwargs['new_level'])
+
+ def _set_zoom_level(self, new_level):
+ logging.debug('new zoom level: %r', new_level)
+ if new_level == shell.ShellModel.ZOOM_MESH:
+ self._mesh_button.props.active = True
+ elif new_level == shell.ShellModel.ZOOM_GROUP:
+ self._groups_button.props.active = True
+ elif new_level == shell.ShellModel.ZOOM_HOME:
+ self._home_button.props.active = True
+ elif new_level == shell.ShellModel.ZOOM_ACTIVITY:
+ self._activity_button.props.active = True
+ else:
+ raise ValueError('Invalid zoom level: %r' % (new_level))
+
diff --git a/shell/src/jarabe/intro/Makefile.am b/shell/src/jarabe/intro/Makefile.am
new file mode 100644
index 0000000..a9fb96b
--- /dev/null
+++ b/shell/src/jarabe/intro/Makefile.am
@@ -0,0 +1,9 @@
+imagedir = $(pythondir)/jarabe/intro
+image_DATA = default-picture.png
+
+EXTRA_DIST = $(conf_DATA) $(image_DATA)
+sugardir = $(pythondir)/jarabe/intro
+sugar_PYTHON = \
+ __init__.py \
+ colorpicker.py \
+ window.py
diff --git a/shell/src/jarabe/intro/__init__.py b/shell/src/jarabe/intro/__init__.py
new file mode 100644
index 0000000..ca4f64d
--- /dev/null
+++ b/shell/src/jarabe/intro/__init__.py
@@ -0,0 +1,25 @@
+import os
+
+import gtk
+
+from sugar import env
+from sugar.profile import get_profile
+
+from jarabe.intro.window import IntroWindow
+from jarabe.intro.window import create_profile
+
+def check_profile():
+ profile = get_profile()
+
+ path = os.path.join(os.path.expanduser('~/.sugar'), 'debug')
+ if not os.path.exists(path):
+ profile.create_debug_file()
+
+ path = os.path.join(env.get_profile_path(), 'config')
+ if os.path.exists(path):
+ profile.convert_profile()
+
+ if not profile.is_valid():
+ win = IntroWindow()
+ win.show_all()
+ gtk.main()
diff --git a/shell/src/jarabe/intro/colorpicker.py b/shell/src/jarabe/intro/colorpicker.py
new file mode 100644
index 0000000..a939857
--- /dev/null
+++ b/shell/src/jarabe/intro/colorpicker.py
@@ -0,0 +1,43 @@
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import hippo
+
+from sugar.graphics.icon import CanvasIcon
+from sugar.graphics import style
+from sugar.graphics.xocolor import XoColor
+
+class ColorPicker(hippo.CanvasBox, hippo.CanvasItem):
+ def __init__(self, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
+ self.props.orientation = hippo.ORIENTATION_HORIZONTAL
+ self._xo_color = None
+
+ self._xo = CanvasIcon(size=style.XLARGE_ICON_SIZE,
+ icon_name='computer-xo')
+ self._set_random_colors()
+ self._xo.connect('activated', self._xo_activated_cb)
+ self.append(self._xo)
+
+ def _xo_activated_cb(self, item):
+ self._set_random_colors()
+
+ def get_color(self):
+ return self._xo_color
+
+ def _set_random_colors(self):
+ self._xo_color = XoColor()
+ self._xo.props.xo_color = self._xo_color
diff --git a/shell/src/jarabe/intro/default-picture.png b/shell/src/jarabe/intro/default-picture.png
new file mode 100644
index 0000000..e26b9b0
--- /dev/null
+++ b/shell/src/jarabe/intro/default-picture.png
Binary files differ
diff --git a/shell/src/jarabe/intro/window.py b/shell/src/jarabe/intro/window.py
new file mode 100644
index 0000000..35c0cda
--- /dev/null
+++ b/shell/src/jarabe/intro/window.py
@@ -0,0 +1,298 @@
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+from gettext import gettext as _
+import gconf
+import pwd
+
+import gtk
+import gobject
+import hippo
+
+from sugar import env
+from sugar.graphics import style
+from sugar.graphics.icon import Icon
+from sugar.graphics.entry import CanvasEntry
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.intro import colorpicker
+
+_BACKGROUND_COLOR = style.COLOR_WHITE
+
+def create_profile(name, color=None, pixbuf=None):
+ if not pixbuf:
+ path = os.path.join(os.path.dirname(__file__), 'default-picture.png')
+ pixbuf = gtk.gdk.pixbuf_new_from_file(path)
+
+ if not color:
+ color = XoColor()
+
+ icon_path = os.path.join(env.get_profile_path(), "buddy-icon.jpg")
+ pixbuf.save(icon_path, "jpeg", {"quality":"85"})
+
+ client = gconf.client_get_default()
+ client.set_string("/desktop/sugar/user/nick", name)
+ client.set_string("/desktop/sugar/user/color", color.to_string())
+
+ # Generate keypair
+ import commands
+ keypath = os.path.join(env.get_profile_path(), "owner.key")
+ if not os.path.isfile(keypath):
+ cmd = "ssh-keygen -q -t dsa -f %s -C '' -N ''" % keypath
+ (s, o) = commands.getstatusoutput(cmd)
+ if s != 0:
+ logging.error("Could not generate key pair: %d %s", s, o)
+ else:
+ logging.error("Keypair exists, skip generation.")
+
+class _Page(hippo.CanvasBox):
+ __gproperties__ = {
+ 'valid' : (bool, None, None, False,
+ gobject.PARAM_READABLE)
+ }
+
+ def __init__(self, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
+ self.valid = False
+
+ def set_valid(self, valid):
+ self.valid = valid
+ self.notify('valid')
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'valid':
+ return self.valid
+
+ def activate(self):
+ pass
+
+class _NamePage(_Page):
+ def __init__(self, intro):
+ _Page.__init__(self, xalign=hippo.ALIGNMENT_CENTER,
+ background_color=_BACKGROUND_COLOR.get_int(),
+ spacing=style.DEFAULT_SPACING,
+ orientation=hippo.ORIENTATION_HORIZONTAL,)
+
+ self._intro = intro
+
+ label = hippo.CanvasText(text=_("Name:"))
+ self.append(label)
+
+ self._entry = CanvasEntry(box_width=style.zoom(300))
+ self._entry.set_background(_BACKGROUND_COLOR.get_html())
+ self._entry.connect('notify::text', self._text_changed_cb)
+
+ widget = self._entry.props.widget
+ widget.set_max_length(45)
+
+ self.append(self._entry)
+
+ if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
+ self.reverse()
+
+ def _text_changed_cb(self, entry, pspec):
+ valid = len(entry.props.text.strip()) > 0
+ self.set_valid(valid)
+
+ def get_name(self):
+ return self._entry.props.text
+
+ def set_name(self, new_name):
+ self._entry.props.text = new_name
+
+ def activate(self):
+ self._entry.props.widget.grab_focus()
+
+class _ColorPage(_Page):
+ def __init__(self, **kwargs):
+ _Page.__init__(self, xalign=hippo.ALIGNMENT_CENTER,
+ background_color=_BACKGROUND_COLOR.get_int(),
+ spacing=style.DEFAULT_SPACING,
+ yalign=hippo.ALIGNMENT_CENTER, **kwargs)
+
+ self._label = hippo.CanvasText(text=_("Click to change color:"),
+ xalign=hippo.ALIGNMENT_CENTER)
+ self.append(self._label)
+
+ self._cp = colorpicker.ColorPicker(xalign=hippo.ALIGNMENT_CENTER)
+ self.append(self._cp)
+
+ self._color = self._cp.get_color()
+ self.set_valid(True)
+
+ def get_color(self):
+ return self._cp.get_color()
+
+class _IntroBox(hippo.CanvasBox):
+ __gsignals__ = {
+ 'done': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
+ }
+
+ PAGE_NAME = 0
+ PAGE_COLOR = 1
+
+ PAGE_FIRST = PAGE_NAME
+ PAGE_LAST = PAGE_COLOR
+
+ def __init__(self):
+ hippo.CanvasBox.__init__(self, padding=style.zoom(30),
+ background_color=_BACKGROUND_COLOR.get_int())
+
+ self._page = self.PAGE_NAME
+ self._name_page = _NamePage(self)
+ self._color_page = _ColorPage()
+ self._current_page = None
+ self._next_button = None
+
+ client = gconf.client_get_default()
+ default_nick = client.get_string('/desktop/sugar/user/default_nick')
+ if default_nick != 'disabled':
+ self._page = self.PAGE_COLOR
+ if default_nick == 'system':
+ pwd_entry = pwd.getpwuid(os.getuid())
+ if pwd_entry.pw_gecos:
+ nick = pwd_entry.pw_gecos.split(',')[0]
+ self._name_page.set_name(nick)
+ else:
+ self._name_page.set_name(pwd_entry.pw_name)
+ else:
+ self._name_page.set_name(default_nick)
+
+ self._setup_page()
+
+ def _setup_page(self):
+ self.remove_all()
+
+ if self._page == self.PAGE_NAME:
+ self._current_page = self._name_page
+ elif self._page == self.PAGE_COLOR:
+ self._current_page = self._color_page
+
+ self.append(self._current_page, hippo.PACK_EXPAND)
+
+ button_box = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL)
+
+ if self._page != self.PAGE_FIRST:
+ back_button = hippo.CanvasButton(text=_('Back'))
+ image = Icon(icon_name='go-left')
+ back_button.props.widget.set_image(image)
+ back_button.connect('activated', self._back_activated_cb)
+ button_box.append(back_button)
+
+ spacer = hippo.CanvasBox()
+ button_box.append(spacer, hippo.PACK_EXPAND)
+
+ self._next_button = hippo.CanvasButton()
+ image = Icon(icon_name='go-right')
+ self._next_button.props.widget.set_image(image)
+
+ if self._page == self.PAGE_LAST:
+ self._next_button.props.text = _('Done')
+ self._next_button.connect('activated', self._done_activated_cb)
+ else:
+ self._next_button.props.text = _('Next')
+ self._next_button.connect('activated', self._next_activated_cb)
+
+ self._current_page.activate()
+
+ self._update_next_button()
+ button_box.append(self._next_button)
+
+ self._current_page.connect('notify::valid',
+ self._page_valid_changed_cb)
+ self.append(button_box)
+
+ if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
+ button_box.reverse()
+
+ def _update_next_button(self):
+ widget = self._next_button.props.widget
+ widget.props.sensitive = self._current_page.props.valid
+
+ def _page_valid_changed_cb(self, page, pspec):
+ self._update_next_button()
+
+ def _back_activated_cb(self, item):
+ self.back()
+
+ def back(self):
+ if self._page != self.PAGE_FIRST:
+ self._page -= 1
+ self._setup_page()
+
+ def _next_activated_cb(self, item):
+ self.next()
+
+ def next(self):
+ if self._page == self.PAGE_LAST:
+ self.done()
+ if self._current_page.props.valid:
+ self._page += 1
+ self._setup_page()
+
+ def _done_activated_cb(self, item):
+ self.done()
+
+ def done(self):
+ name = self._name_page.get_name()
+ color = self._color_page.get_color()
+
+ self.emit('done', name, color)
+
+class IntroWindow(gtk.Window):
+ def __init__(self):
+ gtk.Window.__init__(self)
+
+ self.props.decorated = False
+ self.maximize()
+
+ self._canvas = hippo.Canvas()
+ self._intro_box = _IntroBox()
+ self._intro_box.connect('done', self._done_cb)
+ self._canvas.set_root(self._intro_box)
+
+ self.add(self._canvas)
+ self._canvas.show()
+ self.connect('key-press-event', self.__key_press_cb)
+
+ def _done_cb(self, box, name, color):
+ self.hide()
+ gobject.idle_add(self._create_profile_cb, name, color)
+
+ def _create_profile_cb(self, name, color):
+ create_profile(name, color)
+ gtk.main_quit()
+
+ return False
+
+ def __key_press_cb(self, widget, event):
+ if gtk.gdk.keyval_name(event.keyval) == "Return":
+ self._intro_box.next()
+ return True
+ elif gtk.gdk.keyval_name(event.keyval) == "Escape":
+ self._intro_box.back()
+ return True
+ return False
+
+
+if __name__ == "__main__":
+ w = IntroWindow()
+ w.show()
+ w.connect('destroy', gtk.main_quit)
+ gtk.main()
diff --git a/shell/src/jarabe/journal/Makefile.am b/shell/src/jarabe/journal/Makefile.am
new file mode 100644
index 0000000..f4bf273
--- /dev/null
+++ b/shell/src/jarabe/journal/Makefile.am
@@ -0,0 +1,17 @@
+sugardir = $(pythondir)/jarabe/journal
+sugar_PYTHON = \
+ __init__.py \
+ detailview.py \
+ expandedentry.py \
+ journalactivity.py \
+ journalentrybundle.py \
+ journaltoolbox.py \
+ keepicon.py \
+ listmodel.py \
+ listview.py \
+ misc.py \
+ modalalert.py \
+ model.py \
+ objectchooser.py \
+ palettes.py \
+ volumestoolbar.py
diff --git a/shell/src/jarabe/journal/__init__.py b/shell/src/jarabe/journal/__init__.py
new file mode 100644
index 0000000..6373228
--- /dev/null
+++ b/shell/src/jarabe/journal/__init__.py
@@ -0,0 +1,15 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
diff --git a/shell/src/jarabe/journal/detailview.py b/shell/src/jarabe/journal/detailview.py
new file mode 100644
index 0000000..b4a2339
--- /dev/null
+++ b/shell/src/jarabe/journal/detailview.py
@@ -0,0 +1,117 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+
+import gobject
+import gtk
+import hippo
+
+from sugar.graphics import style
+from sugar.graphics.icon import CanvasIcon
+
+from jarabe.journal.expandedentry import ExpandedEntry
+from jarabe.journal import model
+
+class DetailView(gtk.VBox):
+ __gtype_name__ = 'DetailView'
+
+ __gsignals__ = {
+ 'go-back-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
+ }
+
+ def __init__(self, **kwargs):
+ self._metadata = None
+ self._expanded_entry = None
+
+ canvas = hippo.Canvas()
+
+ self._root = hippo.CanvasBox()
+ self._root.props.background_color = style.COLOR_PANEL_GREY.get_int()
+ canvas.set_root(self._root)
+
+ back_bar = BackBar()
+ back_bar.connect('button-release-event',
+ self.__back_bar_release_event_cb)
+ self._root.append(back_bar)
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ self.pack_start(canvas)
+ canvas.show()
+
+ def _fav_icon_activated_cb(self, fav_icon):
+ keep = not self._expanded_entry.get_keep()
+ self._expanded_entry.set_keep(keep)
+ fav_icon.props.keep = keep
+
+ def __back_bar_release_event_cb(self, back_bar, event):
+ self.emit('go-back-clicked')
+ return False
+
+ def _update_view(self):
+ if self._expanded_entry is None:
+ self._expanded_entry = ExpandedEntry()
+ self._root.append(self._expanded_entry, hippo.PACK_EXPAND)
+ self._expanded_entry.set_metadata(self._metadata)
+
+ def refresh(self):
+ logging.debug('DetailView.refresh')
+ self._metadata = model.get(self._metadata['uid'])
+ self._update_view()
+
+ def get_metadata(self):
+ return self._metadata
+
+ def set_metadata(self, metadata):
+ self._metadata = metadata
+ self._update_view()
+
+ metadata = gobject.property(
+ type=object, getter=get_metadata, setter=set_metadata)
+
+class BackBar(hippo.CanvasBox):
+ def __init__(self):
+ hippo.CanvasBox.__init__(self,
+ orientation=hippo.ORIENTATION_HORIZONTAL,
+ border=style.LINE_WIDTH,
+ background_color=style.COLOR_PANEL_GREY.get_int(),
+ border_color=style.COLOR_SELECTION_GREY.get_int(),
+ padding=style.DEFAULT_PADDING,
+ padding_left=style.DEFAULT_SPACING,
+ spacing=style.DEFAULT_SPACING)
+
+ icon = CanvasIcon(icon_name='go-previous',
+ size=style.SMALL_ICON_SIZE,
+ fill_color=style.COLOR_TOOLBAR_GREY.get_svg())
+ self.append(icon)
+
+ label = hippo.CanvasText(text=_('Back'),
+ font_desc=style.FONT_NORMAL.get_pango_desc())
+ self.append(label)
+
+ if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
+ self.reverse()
+
+ self.connect('motion-notify-event', self.__motion_notify_event_cb)
+
+ def __motion_notify_event_cb(self, box, event):
+ if event.detail == hippo.MOTION_DETAIL_ENTER:
+ box.props.background_color = style.COLOR_SELECTION_GREY.get_int()
+ elif event.detail == hippo.MOTION_DETAIL_LEAVE:
+ box.props.background_color = style.COLOR_PANEL_GREY.get_int()
+ return False
diff --git a/shell/src/jarabe/journal/expandedentry.py b/shell/src/jarabe/journal/expandedentry.py
new file mode 100644
index 0000000..c8e40c1
--- /dev/null
+++ b/shell/src/jarabe/journal/expandedentry.py
@@ -0,0 +1,429 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+import StringIO
+import time
+
+import hippo
+import cairo
+import gobject
+import gtk
+import simplejson
+
+from sugar.graphics import style
+from sugar.graphics.icon import CanvasIcon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.canvastextview import CanvasTextView
+from sugar.util import format_size
+
+from jarabe.journal.keepicon import KeepIcon
+from jarabe.journal.palettes import ObjectPalette, BuddyPalette
+from jarabe.journal import misc
+from jarabe.journal import model
+
+class Separator(hippo.CanvasBox, hippo.CanvasItem):
+ def __init__(self, orientation):
+ hippo.CanvasBox.__init__(self,
+ background_color=style.COLOR_PANEL_GREY.get_int())
+
+ if orientation == hippo.ORIENTATION_VERTICAL:
+ self.props.box_width = style.LINE_WIDTH
+ else:
+ self.props.box_height = style.LINE_WIDTH
+
+class BuddyList(hippo.CanvasBox):
+ def __init__(self, buddies):
+ hippo.CanvasBox.__init__(self, xalign=hippo.ALIGNMENT_START,
+ orientation=hippo.ORIENTATION_HORIZONTAL)
+
+ for buddy in buddies:
+ nick_, color = buddy
+ hbox = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL)
+ icon = CanvasIcon(icon_name='computer-xo',
+ xo_color=XoColor(color),
+ size=style.STANDARD_ICON_SIZE)
+ icon.set_palette(BuddyPalette(buddy))
+ hbox.append(icon)
+ self.append(hbox)
+
+class ExpandedEntry(hippo.CanvasBox):
+ def __init__(self):
+ hippo.CanvasBox.__init__(self)
+ self.props.orientation = hippo.ORIENTATION_VERTICAL
+ self.props.background_color = style.COLOR_WHITE.get_int()
+ self.props.padding_top = style.DEFAULT_SPACING * 3
+
+ self._metadata = None
+ self._update_title_sid = None
+
+ # Create header
+ header = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL,
+ padding=style.DEFAULT_PADDING,
+ padding_right=style.GRID_CELL_SIZE,
+ spacing=style.DEFAULT_SPACING)
+ self.append(header)
+
+ # Create two column body
+
+ body = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL,
+ spacing=style.DEFAULT_SPACING * 3,
+ padding_left=style.GRID_CELL_SIZE,
+ padding_right=style.GRID_CELL_SIZE,
+ padding_top=style.DEFAULT_SPACING * 3)
+
+ self.append(body, hippo.PACK_EXPAND)
+
+ first_column = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL,
+ spacing=style.DEFAULT_SPACING)
+ body.append(first_column)
+
+ second_column = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL,
+ spacing=style.DEFAULT_SPACING)
+ body.append(second_column, hippo.PACK_EXPAND)
+
+ # Header
+
+ self._keep_icon = self._create_keep_icon()
+ header.append(self._keep_icon)
+
+ self._icon = None
+ self._icon_box = hippo.CanvasBox()
+ header.append(self._icon_box)
+
+ self._title = self._create_title()
+ header.append(self._title, hippo.PACK_EXPAND)
+
+ # TODO: create a version list popup instead of a date label
+ self._date = self._create_date()
+ header.append(self._date)
+
+ if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
+ header.reverse()
+
+ # First column
+
+ self._preview_box = hippo.CanvasBox()
+ first_column.append(self._preview_box)
+
+ self._technical_box = hippo.CanvasBox()
+ first_column.append(self._technical_box)
+
+ # Second column
+
+ description_box, self._description = self._create_description()
+ second_column.append(description_box)
+
+ tags_box, self._tags = self._create_tags()
+ second_column.append(tags_box)
+
+ self._buddy_list = hippo.CanvasBox()
+ second_column.append(self._buddy_list)
+
+ def set_metadata(self, metadata):
+ if self._metadata == metadata:
+ return
+ self._metadata = metadata
+
+ self._keep_icon.keep = (int(metadata.get('keep', 0)) == 1)
+
+ self._icon = self._create_icon()
+ self._icon_box.clear()
+ self._icon_box.append(self._icon)
+
+ self._date.props.text = misc.get_date(metadata)
+
+ title = self._title.props.widget
+ title.props.text = metadata.get('title', _('Untitled'))
+ title.props.editable = model.is_editable(metadata)
+
+ self._preview_box.clear()
+ self._preview_box.append(self._create_preview())
+
+ self._technical_box.clear()
+ self._technical_box.append(self._create_technical())
+
+ self._buddy_list.clear()
+ self._buddy_list.append(self._create_buddy_list())
+
+ description = self._description.text_view_widget
+ description.props.buffer.props.text = metadata.get('description', '')
+ description.props.editable = model.is_editable(metadata)
+
+ tags = self._tags.text_view_widget
+ tags.props.buffer.props.text = metadata.get('tags', '')
+ tags.props.editable = model.is_editable(metadata)
+
+ def _create_keep_icon(self):
+ keep_icon = KeepIcon(False)
+ keep_icon.connect('activated', self._keep_icon_activated_cb)
+ return keep_icon
+
+ def _create_icon(self):
+ icon = CanvasIcon(file_name=misc.get_icon_name(self._metadata))
+ icon.connect_after('button-release-event',
+ self._icon_button_release_event_cb)
+
+ if misc.is_activity_bundle(self._metadata):
+ xo_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ else:
+ xo_color = misc.get_icon_color(self._metadata)
+ icon.props.xo_color = xo_color
+
+ icon.set_palette(ObjectPalette(self._metadata))
+
+ return icon
+
+ def _create_title(self):
+ entry = gtk.Entry()
+ entry.connect('focus-out-event', self._title_focus_out_event_cb)
+
+ bg_color = style.COLOR_WHITE.get_gdk_color()
+ entry.modify_bg(gtk.STATE_INSENSITIVE, bg_color)
+ entry.modify_base(gtk.STATE_INSENSITIVE, bg_color)
+
+ return hippo.CanvasWidget(widget=entry)
+
+ def _create_date(self):
+ date = hippo.CanvasText(xalign=hippo.ALIGNMENT_START,
+ font_desc=style.FONT_NORMAL.get_pango_desc())
+ return date
+
+ def _create_preview(self):
+ width = style.zoom(320)
+ height = style.zoom(240)
+ box = hippo.CanvasBox()
+
+ if self._metadata.has_key('preview') and \
+ len(self._metadata['preview']) > 4:
+
+ if self._metadata['preview'][1:4] == 'PNG':
+ preview_data = self._metadata['preview']
+ else:
+ # TODO: We are close to be able to drop this.
+ import base64
+ preview_data = base64.b64decode(
+ self._metadata['preview'])
+
+ png_file = StringIO.StringIO(preview_data)
+ try:
+ surface = cairo.ImageSurface.create_from_png(png_file)
+ has_preview = True
+ except Exception:
+ logging.exception('Error while loading the preview')
+ has_preview = False
+ else:
+ has_preview = False
+
+ if has_preview:
+ preview_box = hippo.CanvasImage(image=surface,
+ border=style.LINE_WIDTH,
+ border_color=style.COLOR_BUTTON_GREY.get_int(),
+ xalign=hippo.ALIGNMENT_CENTER,
+ yalign=hippo.ALIGNMENT_CENTER,
+ scale_width=width,
+ scale_height=height)
+ else:
+ preview_box = hippo.CanvasText(text=_('No preview'),
+ font_desc=style.FONT_NORMAL.get_pango_desc(),
+ xalign=hippo.ALIGNMENT_CENTER,
+ yalign=hippo.ALIGNMENT_CENTER,
+ border=style.LINE_WIDTH,
+ border_color=style.COLOR_BUTTON_GREY.get_int(),
+ color=style.COLOR_BUTTON_GREY.get_int(),
+ box_width=width,
+ box_height=height)
+ preview_box.connect_after('button-release-event',
+ self._preview_box_button_release_event_cb)
+ box.append(preview_box)
+ return box
+
+ def _create_technical(self):
+ vbox = hippo.CanvasBox()
+ vbox.props.spacing = style.DEFAULT_SPACING
+
+ lines = [
+ _('Kind: %s') % (self._metadata.get('mime_type') or _('Unknown'),),
+ _('Date: %s') % (self._format_date(),),
+ _('Size: %s') % (format_size(model.get_file_size(
+ self._metadata['uid'])),)]
+
+ for line in lines:
+ text = hippo.CanvasText(text=line,
+ font_desc=style.FONT_NORMAL.get_pango_desc())
+ text.props.color = style.COLOR_BUTTON_GREY.get_int()
+
+ if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
+ text.props.xalign = hippo.ALIGNMENT_END
+ else:
+ text.props.xalign = hippo.ALIGNMENT_START
+
+ vbox.append(text)
+
+ return vbox
+
+ def _format_date(self):
+ if 'timestamp' in self._metadata:
+ timestamp = float(self._metadata['timestamp'])
+ return time.strftime('%x', time.localtime(timestamp))
+ else:
+ return _('No date')
+
+ def _create_buddy_list(self):
+
+ vbox = hippo.CanvasBox()
+ vbox.props.spacing = style.DEFAULT_SPACING
+
+ text = hippo.CanvasText(text=_('Participants:'),
+ font_desc=style.FONT_NORMAL.get_pango_desc())
+ text.props.color = style.COLOR_BUTTON_GREY.get_int()
+
+ if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
+ text.props.xalign = hippo.ALIGNMENT_END
+ else:
+ text.props.xalign = hippo.ALIGNMENT_START
+
+ vbox.append(text)
+
+ if self._metadata.has_key('buddies') and \
+ self._metadata['buddies']:
+ buddies = simplejson.loads(self._metadata['buddies']).values()
+ vbox.append(BuddyList(buddies))
+ return vbox
+ else:
+ return vbox
+
+ def _create_description(self):
+ vbox = hippo.CanvasBox()
+ vbox.props.spacing = style.DEFAULT_SPACING
+
+ text = hippo.CanvasText(text=_('Description:'),
+ font_desc=style.FONT_NORMAL.get_pango_desc())
+ text.props.color = style.COLOR_BUTTON_GREY.get_int()
+
+ if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
+ text.props.xalign = hippo.ALIGNMENT_END
+ else:
+ text.props.xalign = hippo.ALIGNMENT_START
+
+ vbox.append(text)
+
+ text_view = CanvasTextView('',
+ box_height=style.GRID_CELL_SIZE * 2)
+ vbox.append(text_view, hippo.PACK_EXPAND)
+
+ text_view.text_view_widget.props.accepts_tab = False
+ text_view.text_view_widget.connect('focus-out-event',
+ self._description_focus_out_event_cb)
+
+ return vbox, text_view
+
+ def _create_tags(self):
+ vbox = hippo.CanvasBox()
+ vbox.props.spacing = style.DEFAULT_SPACING
+
+ text = hippo.CanvasText(text=_('Tags:'),
+ font_desc=style.FONT_NORMAL.get_pango_desc())
+ text.props.color = style.COLOR_BUTTON_GREY.get_int()
+
+ if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
+ text.props.xalign = hippo.ALIGNMENT_END
+ else:
+ text.props.xalign = hippo.ALIGNMENT_START
+
+ vbox.append(text)
+
+ text_view = CanvasTextView('',
+ box_height=style.GRID_CELL_SIZE * 2)
+ vbox.append(text_view, hippo.PACK_EXPAND)
+
+ text_view.text_view_widget.props.accepts_tab = False
+ text_view.text_view_widget.connect('focus-out-event',
+ self._tags_focus_out_event_cb)
+
+ return vbox, text_view
+
+ def _title_notify_text_cb(self, entry, pspec):
+ if not self._update_title_sid:
+ self._update_title_sid = gobject.timeout_add_seconds(1,
+ self._update_title_cb)
+
+ def _title_focus_out_event_cb(self, entry, event):
+ self._update_entry()
+
+ def _description_focus_out_event_cb(self, text_view, event):
+ self._update_entry()
+
+ def _tags_focus_out_event_cb(self, text_view, event):
+ self._update_entry()
+
+ def _update_entry(self):
+ if not model.is_editable(self._metadata):
+ return
+
+ needs_update = False
+
+ old_title = self._metadata.get('title', None)
+ new_title = self._title.props.widget.props.text
+ if old_title != new_title:
+ self._icon.palette.props.primary_text = new_title
+ self._metadata['title'] = new_title
+ self._metadata['title_set_by_user'] = '1'
+ needs_update = True
+
+ old_tags = self._metadata.get('tags', None)
+ new_tags = self._tags.text_view_widget.props.buffer.props.text
+ if old_tags != new_tags:
+ self._metadata['tags'] = new_tags
+ needs_update = True
+
+ old_description = self._metadata.get('description', None)
+ new_description = \
+ self._description.text_view_widget.props.buffer.props.text
+ if old_description != new_description:
+ self._metadata['description'] = new_description
+ needs_update = True
+
+ if needs_update:
+ model.write(self._metadata, update_mtime=False)
+
+ self._update_title_sid = None
+
+ def get_keep(self):
+ return int(self._metadata.get('keep', 0)) == 1
+
+ def _keep_icon_activated_cb(self, keep_icon):
+ if not model.is_editable(self._metadata):
+ return
+ if self.get_keep():
+ self._metadata['keep'] = 0
+ else:
+ self._metadata['keep'] = 1
+ model.write(self._metadata, update_mtime=False)
+
+ keep_icon.props.keep = self.get_keep()
+
+ def _icon_button_release_event_cb(self, button, event):
+ logging.debug('_icon_button_release_event_cb')
+ misc.resume(self._metadata)
+ return True
+
+ def _preview_box_button_release_event_cb(self, button, event):
+ logging.debug('_preview_box_button_release_event_cb')
+ misc.resume(self._metadata)
+ return True
diff --git a/shell/src/jarabe/journal/journalactivity.py b/shell/src/jarabe/journal/journalactivity.py
new file mode 100644
index 0000000..e278420
--- /dev/null
+++ b/shell/src/jarabe/journal/journalactivity.py
@@ -0,0 +1,371 @@
+# Copyright (C) 2006, Red Hat, Inc.
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+import sys
+import traceback
+import uuid
+
+import gtk
+import dbus
+import statvfs
+import os
+
+from sugar.graphics.window import Window
+from sugar.graphics.alert import ErrorAlert
+
+from sugar.bundle.bundle import ZipExtractException, RegistrationException
+from sugar import env
+from sugar.activity import activityfactory
+from sugar import wm
+
+from jarabe.model import bundleregistry
+from jarabe.journal.journaltoolbox import MainToolbox, DetailToolbox
+from jarabe.journal.listview import ListView
+from jarabe.journal.detailview import DetailView
+from jarabe.journal.volumestoolbar import VolumesToolbar
+from jarabe.journal import misc
+from jarabe.journal.journalentrybundle import JournalEntryBundle
+from jarabe.journal.objectchooser import ObjectChooser
+from jarabe.journal.modalalert import ModalAlert
+from jarabe.journal import model
+
+J_DBUS_SERVICE = 'org.laptop.Journal'
+J_DBUS_INTERFACE = 'org.laptop.Journal'
+J_DBUS_PATH = '/org/laptop/Journal'
+
+_SPACE_TRESHOLD = 52428800
+_BUNDLE_ID = 'org.laptop.JournalActivity'
+
+class JournalActivityDBusService(dbus.service.Object):
+ def __init__(self, parent):
+ self._parent = parent
+ session_bus = dbus.SessionBus()
+ bus_name = dbus.service.BusName(J_DBUS_SERVICE,
+ bus=session_bus, replace_existing=False, allow_replacement=False)
+ logging.debug('bus_name: %r', bus_name)
+ dbus.service.Object.__init__(self, bus_name, J_DBUS_PATH)
+
+ @dbus.service.method(J_DBUS_INTERFACE,
+ in_signature='s', out_signature='')
+ def ShowObject(self, object_id):
+ """Pop-up journal and show object with object_id"""
+
+ logging.debug('Trying to show object %s', object_id)
+
+ if self._parent.show_object(object_id):
+ self._parent.reveal()
+
+ def _chooser_response_cb(self, chooser, response_id, chooser_id):
+ logging.debug('JournalActivityDBusService._chooser_response_cb')
+ if response_id == gtk.RESPONSE_ACCEPT:
+ object_id = chooser.get_selected_object_id()
+ self.ObjectChooserResponse(chooser_id, object_id)
+ else:
+ self.ObjectChooserCancelled(chooser_id)
+ chooser.destroy()
+ del chooser
+
+ @dbus.service.method(J_DBUS_INTERFACE, in_signature='is', out_signature='s')
+ def ChooseObject(self, parent_xid, what_filter=''):
+ chooser_id = uuid.uuid4().hex
+ if parent_xid > 0:
+ parent = gtk.gdk.window_foreign_new(parent_xid)
+ else:
+ parent = None
+ chooser = ObjectChooser(parent, what_filter)
+ chooser.connect('response', self._chooser_response_cb, chooser_id)
+ chooser.show()
+
+ return chooser_id
+
+ @dbus.service.signal(J_DBUS_INTERFACE, signature="ss")
+ def ObjectChooserResponse(self, chooser_id, object_id):
+ pass
+
+ @dbus.service.signal(J_DBUS_INTERFACE, signature="s")
+ def ObjectChooserCancelled(self, chooser_id):
+ pass
+
+class JournalActivity(Window):
+ def __init__(self):
+ logging.debug("STARTUP: Loading the journal")
+ Window.__init__(self)
+
+ self.set_title(_('Journal'))
+
+ self._main_view = None
+ self._secondary_view = None
+ self._list_view = None
+ self._detail_view = None
+ self._main_toolbox = None
+ self._detail_toolbox = None
+ self._volumes_toolbar = None
+
+ self._setup_main_view()
+ self._setup_secondary_view()
+
+ self.add_events(gtk.gdk.ALL_EVENTS_MASK |
+ gtk.gdk.VISIBILITY_NOTIFY_MASK)
+ self._realized_sid = self.connect('realize', self.__realize_cb)
+ self.connect('visibility-notify-event',
+ self.__visibility_notify_event_cb)
+ self.connect('window-state-event', self.__window_state_event_cb)
+ self.connect('key-press-event', self._key_press_event_cb)
+ self.connect('focus-in-event', self._focus_in_event_cb)
+
+ model.created.connect(self.__model_created_cb)
+ model.updated.connect(self.__model_updated_cb)
+ model.deleted.connect(self.__model_deleted_cb)
+
+ self._dbus_service = JournalActivityDBusService(self)
+
+ self.iconify()
+
+ self._critical_space_alert = None
+ self._check_available_space()
+
+ def __alert_notify_cb(self, gobject, strerror, severity):
+ alert = ErrorAlert(title=severity, msg=strerror)
+ alert.connect('response', self.__alert_response_cb)
+ self.add_alert(alert)
+ alert.show()
+
+ def __alert_response_cb(self, alert, response_id):
+ self.remove_alert(alert)
+
+ def __realize_cb(self, window):
+ wm.set_bundle_id(window.window, _BUNDLE_ID)
+ activity_id = activityfactory.create_activity_id()
+ wm.set_activity_id(window.window, str(activity_id))
+ self.disconnect(self._realized_sid)
+ self._realized_sid = None
+
+ def can_close(self):
+ return False
+
+ def _setup_main_view(self):
+ self._main_toolbox = MainToolbox()
+ self._main_view = gtk.VBox()
+
+ self._list_view = ListView()
+ self._list_view.connect('detail-clicked', self.__detail_clicked_cb)
+ self._list_view.connect('clear-clicked', self.__clear_clicked_cb)
+ self._main_view.pack_start(self._list_view)
+ self._list_view.show()
+
+ self._volumes_toolbar = VolumesToolbar()
+ self._volumes_toolbar.connect('volume-changed',
+ self.__volume_changed_cb)
+ self._volumes_toolbar.connect('volume-error', self.__alert_notify_cb)
+ self._main_view.pack_start(self._volumes_toolbar, expand=False)
+
+ search_toolbar = self._main_toolbox.search_toolbar
+ search_toolbar.connect('query-changed', self._query_changed_cb)
+ search_toolbar.set_mount_point('/')
+
+ def _setup_secondary_view(self):
+ self._secondary_view = gtk.VBox()
+
+ self._detail_toolbox = DetailToolbox()
+ entry_toolbar = self._detail_toolbox.entry_toolbar
+
+ self._detail_view = DetailView()
+ self._detail_view.connect('go-back-clicked', self.__go_back_clicked_cb)
+ self._secondary_view.pack_end(self._detail_view)
+ self._detail_view.show()
+
+ def _key_press_event_cb(self, widget, event):
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == 'Escape':
+ self.show_main_view()
+
+ def __detail_clicked_cb(self, list_view, object_id):
+ self._show_secondary_view(object_id)
+
+ def __clear_clicked_cb(self, list_view):
+ self._main_toolbox.search_toolbar.clear_query()
+
+ def __go_back_clicked_cb(self, detail_view):
+ self.show_main_view()
+
+ def _query_changed_cb(self, toolbar, query):
+ self._list_view.update_with_query(query)
+ self.show_main_view()
+
+ def show_main_view(self):
+ if self.toolbar_box != self._main_toolbox:
+ self.set_toolbar_box(self._main_toolbox)
+ self._main_toolbox.show()
+
+ if self.canvas != self._main_view:
+ self.set_canvas(self._main_view)
+ self._main_view.show()
+
+ def _show_secondary_view(self, object_id):
+ metadata = model.get(object_id)
+ try:
+ self._detail_toolbox.entry_toolbar.set_metadata(metadata)
+ except Exception:
+ logging.error('Exception while displaying entry:\n' + \
+ ''.join(traceback.format_exception(*sys.exc_info())))
+
+ self.set_toolbar_box(self._detail_toolbox)
+ self._detail_toolbox.show()
+
+ try:
+ self._detail_view.props.metadata = metadata
+ except Exception:
+ logging.error('Exception while displaying entry:\n' + \
+ ''.join(traceback.format_exception(*sys.exc_info())))
+
+ self.set_canvas(self._secondary_view)
+ self._secondary_view.show()
+
+ def show_object(self, object_id):
+ metadata = model.get(object_id)
+ if metadata is None:
+ return False
+ else:
+ self._show_secondary_view(object_id)
+ return True
+
+ def __volume_changed_cb(self, volume_toolbar, mount_point):
+ logging.debug('Selected volume: %r.', mount_point)
+ self._main_toolbox.search_toolbar.set_mount_point(mount_point)
+ self._main_toolbox.set_current_toolbar(0)
+
+ def __model_created_cb(self, sender, **kwargs):
+ self._check_for_bundle(kwargs['object_id'])
+ self._main_toolbox.search_toolbar.refresh_filters()
+ self._check_available_space()
+
+ def __model_updated_cb(self, sender, **kwargs):
+ self._check_for_bundle(kwargs['object_id'])
+
+ if self.canvas == self._secondary_view and \
+ kwargs['object_id'] == self._detail_view.props.metadata['uid']:
+ self._detail_view.refresh()
+
+ self._check_available_space()
+
+ def __model_deleted_cb(self, sender, **kwargs):
+ if self.canvas == self._secondary_view and \
+ kwargs['object_id'] == self._detail_view.props.metadata['uid']:
+ self.show_main_view()
+
+ def _focus_in_event_cb(self, window, event):
+ self.search_grab_focus()
+ self._list_view.update_dates()
+
+ def _check_for_bundle(self, object_id):
+ registry = bundleregistry.get_registry()
+
+ metadata = model.get(object_id)
+ if metadata.get('progress', '').isdigit():
+ if int(metadata['progress']) < 100:
+ return
+
+ bundle = misc.get_bundle(metadata)
+ if bundle is None:
+ return
+
+ if registry.is_installed(bundle):
+ logging.debug('_check_for_bundle bundle already installed')
+ return
+
+ if metadata['mime_type'] == JournalEntryBundle.MIME_TYPE:
+ # JournalEntryBundle code takes over the datastore entry and
+ # transforms it into the journal entry from the bundle -- we have
+ # nothing more to do.
+ try:
+ registry.install(bundle, metadata['uid'])
+ except (ZipExtractException, RegistrationException):
+ logging.exception('Could not install bundle %s',
+ bundle.get_path())
+ return
+
+ try:
+ registry.install(bundle)
+ except (ZipExtractException, RegistrationException):
+ logging.exception('Could not install bundle %s', bundle.get_path())
+ return
+
+ metadata['bundle_id'] = bundle.get_bundle_id()
+ model.write(metadata)
+
+ def search_grab_focus(self):
+ search_toolbar = self._main_toolbox.search_toolbar
+ search_toolbar.give_entry_focus()
+
+ def __window_state_event_cb(self, window, event):
+ logging.debug('window_state_event_cb %r', self)
+ if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
+ state = event.new_window_state
+ visible = not state & gtk.gdk.WINDOW_STATE_ICONIFIED
+ self._list_view.set_is_visible(visible)
+
+ def __visibility_notify_event_cb(self, window, event):
+ logging.debug('visibility_notify_event_cb %r', self)
+ visible = event.state != gtk.gdk.VISIBILITY_FULLY_OBSCURED
+ self._list_view.set_is_visible(visible)
+
+ def _check_available_space(self):
+ ''' Check available space on device
+
+ If the available space is below 50MB an alert will be
+ shown which encourages to delete old journal entries.
+ '''
+
+ if self._critical_space_alert:
+ return
+ stat = os.statvfs(env.get_profile_path())
+ free_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL]
+ if free_space < _SPACE_TRESHOLD:
+ self._critical_space_alert = ModalAlert()
+ self._critical_space_alert.connect('destroy',
+ self.__alert_closed_cb)
+ self._critical_space_alert.show()
+
+ def __alert_closed_cb(self, data):
+ self.show_main_view()
+ self.reveal()
+ self._critical_space_alert = None
+
+ def set_active_volume(self, mount):
+ self._volumes_toolbar.set_active_volume(mount)
+
+ def focus_search(self):
+ """Become visible and give focus to the search entry
+ """
+ self.reveal()
+ self.show_main_view()
+ self.search_grab_focus()
+
+_journal = None
+
+def get_journal():
+ global _journal
+ if _journal is None:
+ _journal = JournalActivity()
+ _journal.show()
+ return _journal
+
+def start():
+ get_journal()
+
diff --git a/shell/src/jarabe/journal/journalentrybundle.py b/shell/src/jarabe/journal/journalentrybundle.py
new file mode 100644
index 0000000..41777c7
--- /dev/null
+++ b/shell/src/jarabe/journal/journalentrybundle.py
@@ -0,0 +1,94 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import tempfile
+import shutil
+
+import simplejson
+import dbus
+
+from sugar.bundle.bundle import Bundle, MalformedBundleException
+
+from jarabe.journal import model
+
+class JournalEntryBundle(Bundle):
+ """A Journal entry bundle
+
+ See http://wiki.laptop.org/go/Journal_entry_bundles for details
+ """
+
+ MIME_TYPE = 'application/vnd.olpc-journal-entry'
+
+ _zipped_extension = '.xoj'
+ _unzipped_extension = None
+ _infodir = None
+
+ def __init__(self, path):
+ Bundle.__init__(self, path)
+
+ def install(self, uid=''):
+ if os.environ.has_key('SUGAR_ACTIVITY_ROOT'):
+ install_dir = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],
+ 'data')
+ else:
+ install_dir = tempfile.gettempdir()
+ bundle_dir = os.path.join(install_dir, self._zip_root_dir)
+ temp_uid = self._zip_root_dir
+ self._unzip(install_dir)
+ try:
+ metadata = self._read_metadata(bundle_dir)
+ metadata['uid'] = uid
+
+ preview = self._read_preview(temp_uid, bundle_dir)
+ if preview is not None:
+ metadata['preview'] = dbus.ByteArray(preview)
+
+ file_path = os.path.join(bundle_dir, temp_uid)
+ model.write(metadata, file_path)
+ finally:
+ shutil.rmtree(bundle_dir, ignore_errors=True)
+
+ def get_bundle_id(self):
+ return None
+
+ def _read_metadata(self, bundle_dir):
+ metadata_path = os.path.join(bundle_dir, '_metadata.json')
+ if not os.path.exists(metadata_path):
+ raise MalformedBundleException(
+ 'Bundle must contain the file "_metadata.json"')
+ f = open(metadata_path, 'r')
+ try:
+ json_data = f.read()
+ finally:
+ f.close()
+ return simplejson.loads(json_data)
+
+ def _read_preview(self, uid, bundle_dir):
+ preview_path = os.path.join(bundle_dir, 'preview', uid)
+ if not os.path.exists(preview_path):
+ return ''
+ f = open(preview_path, 'r')
+ try:
+ preview_data = f.read()
+ finally:
+ f.close()
+ return preview_data
+
+ def is_installed(self):
+ # These bundles can be reinstalled as many times as desired.
+ return False
+
diff --git a/shell/src/jarabe/journal/journaltoolbox.py b/shell/src/jarabe/journal/journaltoolbox.py
new file mode 100644
index 0000000..61671bc
--- /dev/null
+++ b/shell/src/jarabe/journal/journaltoolbox.py
@@ -0,0 +1,458 @@
+# Copyright (C) 2007, One Laptop Per Child
+# Copyright (C) 2009, Walter Bender
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+from datetime import datetime, timedelta
+import os
+import gconf
+import time
+
+import gobject
+import gio
+import gtk
+
+from sugar.graphics.toolbox import Toolbox
+from sugar.graphics.toolcombobox import ToolComboBox
+from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics.toggletoolbutton import ToggleToolButton
+from sugar.graphics.combobox import ComboBox
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.icon import Icon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics import iconentry
+from sugar.graphics import style
+from sugar import mime
+from sugar import profile
+
+from jarabe.model import bundleregistry
+from jarabe.journal import misc
+from jarabe.journal import model
+
+_AUTOSEARCH_TIMEOUT = 1000
+
+_ACTION_ANYTIME = 0
+_ACTION_TODAY = 1
+_ACTION_SINCE_YESTERDAY = 2
+_ACTION_PAST_WEEK = 3
+_ACTION_PAST_MONTH = 4
+_ACTION_PAST_YEAR = 5
+
+_ACTION_ANYTHING = 0
+
+_ACTION_EVERYBODY = 0
+_ACTION_MY_FRIENDS = 1
+_ACTION_MY_CLASS = 2
+
+
+class MainToolbox(Toolbox):
+ def __init__(self):
+ Toolbox.__init__(self)
+
+ self.search_toolbar = SearchToolbar()
+ self.search_toolbar.set_size_request(-1, style.GRID_CELL_SIZE)
+ self.add_toolbar(_('Search'), self.search_toolbar)
+ self.search_toolbar.show()
+
+class SearchToolbar(gtk.Toolbar):
+ __gtype_name__ = 'SearchToolbar'
+
+ __gsignals__ = {
+ 'query-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([object]))
+ }
+
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self._mount_point = None
+
+ self._search_entry = iconentry.IconEntry()
+ self._search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY,
+ 'system-search')
+ self._search_entry.connect('activate', self._search_entry_activated_cb)
+ self._search_entry.connect('changed', self._search_entry_changed_cb)
+ self._search_entry.add_clear_button()
+ self._autosearch_timer = None
+ self._add_widget(self._search_entry, expand=True)
+
+ self._favorite_button = ToggleToolButton('emblem-favorite')
+ self._favorite_button.connect('toggled',
+ self.__favorite_button_toggled_cb)
+ self.insert(self._favorite_button, -1)
+ self._favorite_button.show()
+
+ self._what_search_combo = ComboBox()
+ self._what_combo_changed_sid = self._what_search_combo.connect(
+ 'changed', self._combo_changed_cb)
+ tool_item = ToolComboBox(self._what_search_combo)
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ self._when_search_combo = self._get_when_search_combo()
+ tool_item = ToolComboBox(self._when_search_combo)
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ # TODO: enable it when the DS supports saving the buddies.
+ #self._with_search_combo = self._get_with_search_combo()
+ #tool_item = ToolComboBox(self._with_search_combo)
+ #self.insert(tool_item, -1)
+ #tool_item.show()
+
+ self._query = self._build_query()
+
+ self.refresh_filters()
+
+ def give_entry_focus(self):
+ self._search_entry.grab_focus()
+
+ def _get_when_search_combo(self):
+ when_search = ComboBox()
+ when_search.append_item(_ACTION_ANYTIME, _('Anytime'))
+ when_search.append_separator()
+ when_search.append_item(_ACTION_TODAY, _('Today'))
+ when_search.append_item(_ACTION_SINCE_YESTERDAY,
+ _('Since yesterday'))
+ # TRANS: Filter entries modified during the last 7 days.
+ when_search.append_item(_ACTION_PAST_WEEK, _('Past week'))
+ # TRANS: Filter entries modified during the last 30 days.
+ when_search.append_item(_ACTION_PAST_MONTH, _('Past month'))
+ # TRANS: Filter entries modified during the last 356 days.
+ when_search.append_item(_ACTION_PAST_YEAR, _('Past year'))
+ when_search.set_active(0)
+ when_search.connect('changed', self._combo_changed_cb)
+ return when_search
+
+ def _get_with_search_combo(self):
+ with_search = ComboBox()
+ with_search.append_item(_ACTION_EVERYBODY, _('Anyone'))
+ with_search.append_separator()
+ with_search.append_item(_ACTION_MY_FRIENDS, _('My friends'))
+ with_search.append_item(_ACTION_MY_CLASS, _('My class'))
+ with_search.append_separator()
+
+ # TODO: Ask the model for buddies.
+ with_search.append_item(3, 'Dan', 'theme:xo')
+
+ with_search.set_active(0)
+ with_search.connect('changed', self._combo_changed_cb)
+ return with_search
+
+ def _add_widget(self, widget, expand=False):
+ tool_item = gtk.ToolItem()
+ tool_item.set_expand(expand)
+
+ tool_item.add(widget)
+ widget.show()
+
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ def _build_query(self):
+ query = {}
+
+ if self._mount_point:
+ query['mountpoints'] = [self._mount_point]
+
+ if self._favorite_button.props.active:
+ query['keep'] = 1
+
+ if self._what_search_combo.props.value:
+ value = self._what_search_combo.props.value
+ generic_type = mime.get_generic_type(value)
+ if generic_type:
+ mime_types = generic_type.mime_types
+ query['mime_type'] = mime_types
+ else:
+ query['activity'] = self._what_search_combo.props.value
+
+ if self._when_search_combo.props.value:
+ date_from, date_to = self._get_date_range()
+ query['timestamp'] = {'start': date_from, 'end': date_to}
+
+ if self._search_entry.props.text:
+ text = self._search_entry.props.text.strip()
+ if text:
+ query['query'] = text
+
+ return query
+
+ def _get_date_range(self):
+ today_start = datetime.today().replace(hour=0, minute=0, second=0)
+ right_now = datetime.today()
+ if self._when_search_combo.props.value == _ACTION_TODAY:
+ date_range = (today_start, right_now)
+ elif self._when_search_combo.props.value == _ACTION_SINCE_YESTERDAY:
+ date_range = (today_start - timedelta(1), right_now)
+ elif self._when_search_combo.props.value == _ACTION_PAST_WEEK:
+ date_range = (today_start - timedelta(7), right_now)
+ elif self._when_search_combo.props.value == _ACTION_PAST_MONTH:
+ date_range = (today_start - timedelta(30), right_now)
+ elif self._when_search_combo.props.value == _ACTION_PAST_YEAR:
+ date_range = (today_start - timedelta(356), right_now)
+
+ return (time.mktime(date_range[0].timetuple()),
+ time.mktime(date_range[1].timetuple()))
+
+ def _combo_changed_cb(self, combo):
+ self._update_if_needed()
+
+ def _update_if_needed(self):
+ new_query = self._build_query()
+ if self._query != new_query:
+ self._query = new_query
+ self.emit('query-changed', self._query)
+
+ def _search_entry_activated_cb(self, search_entry):
+ if self._autosearch_timer:
+ gobject.source_remove(self._autosearch_timer)
+ new_query = self._build_query()
+ if self._query != new_query:
+ self._query = new_query
+ self.emit('query-changed', self._query)
+
+ def _search_entry_changed_cb(self, search_entry):
+ if not search_entry.props.text:
+ search_entry.activate()
+ return
+
+ if self._autosearch_timer:
+ gobject.source_remove(self._autosearch_timer)
+ self._autosearch_timer = gobject.timeout_add(_AUTOSEARCH_TIMEOUT,
+ self._autosearch_timer_cb)
+
+ def _autosearch_timer_cb(self):
+ logging.debug('_autosearch_timer_cb')
+ self._autosearch_timer = None
+ self._search_entry.activate()
+ return False
+
+ def set_mount_point(self, mount_point):
+ self._mount_point = mount_point
+ new_query = self._build_query()
+ if self._query != new_query:
+ self._query = new_query
+ self.emit('query-changed', self._query)
+
+ def set_what_filter(self, what_filter):
+ combo_model = self._what_search_combo.get_model()
+ what_filter_index = -1
+ for i in range(0, len(combo_model) - 1):
+ if combo_model[i][0] == what_filter:
+ what_filter_index = i
+ break
+
+ if what_filter_index == -1:
+ logging.warning('what_filter %r not known', what_filter)
+ else:
+ self._what_search_combo.set_active(what_filter_index)
+
+ def refresh_filters(self):
+ current_value = self._what_search_combo.props.value
+ current_value_index = 0
+
+ self._what_search_combo.handler_block(self._what_combo_changed_sid)
+ try:
+ self._what_search_combo.remove_all()
+ # TRANS: Item in a combo box that filters by entry type.
+ self._what_search_combo.append_item(_ACTION_ANYTHING,
+ _('Anything'))
+
+ registry = bundleregistry.get_registry()
+ appended_separator = False
+
+ types = mime.get_all_generic_types()
+ for generic_type in types:
+ if not appended_separator:
+ self._what_search_combo.append_separator()
+ appended_separator = True
+ self._what_search_combo.append_item(
+ generic_type.type_id, generic_type.name, generic_type.icon)
+ if generic_type.type_id == current_value:
+ current_value_index = \
+ len(self._what_search_combo.get_model()) - 1
+
+ self._what_search_combo.set_active(current_value_index)
+
+ self._what_search_combo.append_separator()
+
+ for service_name in model.get_unique_values('activity'):
+ activity_info = registry.get_bundle(service_name)
+ if not activity_info is None:
+ if os.path.exists(activity_info.get_icon()):
+ self._what_search_combo.append_item(service_name,
+ activity_info.get_name(),
+ file_name=activity_info.get_icon())
+ else:
+ self._what_search_combo.append_item(service_name,
+ activity_info.get_name(),
+ icon_name='application-octet-stream')
+
+ if service_name == current_value:
+ current_value_index = \
+ len(self._what_search_combo.get_model()) - 1
+ finally:
+ self._what_search_combo.handler_unblock(
+ self._what_combo_changed_sid)
+
+ def __favorite_button_toggled_cb(self, favorite_button):
+ self._update_if_needed()
+
+ def clear_query(self):
+ self._search_entry.props.text = ''
+ self._what_search_combo.set_active(0)
+ self._when_search_combo.set_active(0)
+ self._favorite_button.props.active = False
+
+class DetailToolbox(Toolbox):
+ def __init__(self):
+ Toolbox.__init__(self)
+
+ self.entry_toolbar = EntryToolbar()
+ self.add_toolbar('', self.entry_toolbar)
+ self.entry_toolbar.show()
+
+class EntryToolbar(gtk.Toolbar):
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self._metadata = None
+ self._temp_file_path = None
+
+ self._resume = ToolButton('activity-start')
+ self._resume.connect('clicked', self._resume_clicked_cb)
+ self.add(self._resume)
+ self._resume.show()
+
+ self._copy = ToolButton()
+
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ icon = Icon(icon_name='edit-copy', xo_color=color)
+ self._copy.set_icon_widget(icon)
+ icon.show()
+
+ self._copy.set_tooltip(_('Copy'))
+ self._copy.connect('clicked', self._copy_clicked_cb)
+ self.add(self._copy)
+ self._copy.show()
+
+ separator = gtk.SeparatorToolItem()
+ self.add(separator)
+ separator.show()
+
+ erase_button = ToolButton('list-remove')
+ erase_button.set_tooltip(_('Erase'))
+ erase_button.connect('clicked', self._erase_button_clicked_cb)
+ self.add(erase_button)
+ erase_button.show()
+
+ def set_metadata(self, metadata):
+ self._metadata = metadata
+ self._refresh_copy_palette()
+ self._refresh_resume_palette()
+
+ def _resume_clicked_cb(self, button):
+ misc.resume(self._metadata)
+
+ def _copy_clicked_cb(self, button):
+ clipboard = gtk.Clipboard()
+ clipboard.set_with_data([('text/uri-list', 0, 0)],
+ self.__clipboard_get_func_cb,
+ self.__clipboard_clear_func_cb)
+
+ def __clipboard_get_func_cb(self, clipboard, selection_data, info, data):
+ # Get hold of a reference so the temp file doesn't get deleted
+ self._temp_file_path = model.get_file(self._metadata['uid'])
+ selection_data.set_uris(['file://' + self._temp_file_path])
+
+ def __clipboard_clear_func_cb(self, clipboard, data):
+ # Release and delete the temp file
+ self._temp_file_path = None
+
+ def _erase_button_clicked_cb(self, button):
+ registry = bundleregistry.get_registry()
+
+ bundle = misc.get_bundle(self._metadata)
+ if bundle is not None and registry.is_installed(bundle):
+ registry.uninstall(bundle)
+ model.delete(self._metadata['uid'])
+
+ def _resume_menu_item_activate_cb(self, menu_item, service_name):
+ misc.resume(self._metadata, service_name)
+
+ def _copy_menu_item_activate_cb(self, menu_item, mount_point):
+ model.copy(self._metadata, mount_point)
+
+ def _refresh_copy_palette(self):
+ palette = self._copy.get_palette()
+
+ for menu_item in palette.menu.get_children():
+ palette.menu.remove(menu_item)
+ menu_item.destroy()
+
+ if self._metadata['mountpoint'] != '/':
+ journal_item = MenuItem(_('Journal'))
+ journal_item.set_image(Icon(
+ icon_name='activity-journal',
+ xo_color=profile.get_color(),
+ icon_size=gtk.ICON_SIZE_MENU))
+ journal_item.connect('activate',
+ self._copy_menu_item_activate_cb, '/')
+ journal_item.show()
+ palette.menu.append(journal_item)
+
+ volume_monitor = gio.volume_monitor_get()
+ for mount in volume_monitor.get_mounts():
+ if self._metadata['mountpoint'] == mount.get_root().get_path():
+ continue
+ menu_item = MenuItem(mount.get_name())
+
+ # TODO: fallback to the more generic icons when needed
+ menu_item.set_image(Icon(icon_name=mount.get_icon().props.names[0],
+ icon_size=gtk.ICON_SIZE_MENU))
+
+ menu_item.connect('activate',
+ self._copy_menu_item_activate_cb,
+ mount.get_root().get_path())
+ palette.menu.append(menu_item)
+ menu_item.show()
+
+ def _refresh_resume_palette(self):
+ if self._metadata.get('activity_id', ''):
+ # TRANS: Action label for resuming an activity.
+ self._resume.set_tooltip(_('Resume'))
+ else:
+ # TRANS: Action label for starting an entry.
+ self._resume.set_tooltip(_('Start'))
+
+ palette = self._resume.get_palette()
+
+ for menu_item in palette.menu.get_children():
+ palette.menu.remove(menu_item)
+ menu_item.destroy()
+
+ for activity_info in misc.get_activities(self._metadata):
+ menu_item = MenuItem(activity_info.get_name())
+ menu_item.set_image(Icon(file=activity_info.get_icon(),
+ icon_size=gtk.ICON_SIZE_MENU))
+ menu_item.connect('activate', self._resume_menu_item_activate_cb,
+ activity_info.get_bundle_id())
+ palette.menu.append(menu_item)
+ menu_item.show()
diff --git a/shell/src/jarabe/journal/keepicon.py b/shell/src/jarabe/journal/keepicon.py
new file mode 100644
index 0000000..2c692c6
--- /dev/null
+++ b/shell/src/jarabe/journal/keepicon.py
@@ -0,0 +1,59 @@
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gobject
+import hippo
+import gconf
+
+from sugar.graphics.icon import CanvasIcon
+from sugar.graphics import style
+from sugar.graphics.xocolor import XoColor
+
+class KeepIcon(CanvasIcon):
+ def __init__(self, keep):
+ CanvasIcon.__init__(self, icon_name='emblem-favorite',
+ box_width=style.GRID_CELL_SIZE * 3 / 5,
+ size=style.SMALL_ICON_SIZE)
+ self.connect('motion-notify-event', self.__motion_notify_event_cb)
+
+ self._keep = None
+ self.set_keep(keep)
+
+ def set_keep(self, keep):
+ if keep == self._keep:
+ return
+
+ self._keep = keep
+ if keep:
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ self.props.xo_color = color
+ else:
+ self.props.stroke_color = style.COLOR_BUTTON_GREY.get_svg()
+ self.props.fill_color = style.COLOR_TRANSPARENT.get_svg()
+
+ def get_keep(self):
+ return self._keep
+
+ keep = gobject.property(type=int, default=0, getter=get_keep,
+ setter=set_keep)
+
+ def __motion_notify_event_cb(self, icon, event):
+ if not self._keep:
+ if event.detail == hippo.MOTION_DETAIL_ENTER:
+ icon.props.fill_color = style.COLOR_BUTTON_GREY.get_svg()
+ elif event.detail == hippo.MOTION_DETAIL_LEAVE:
+ icon.props.fill_color = style.COLOR_TRANSPARENT.get_svg()
diff --git a/shell/src/jarabe/journal/listmodel.py b/shell/src/jarabe/journal/listmodel.py
new file mode 100644
index 0000000..07f8544
--- /dev/null
+++ b/shell/src/jarabe/journal/listmodel.py
@@ -0,0 +1,201 @@
+# Copyright (C) 2009, Tomeu Vizoso
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import simplejson
+import gobject
+import gtk
+
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics import style
+from sugar import util
+
+from jarabe.journal import model
+from jarabe.journal import misc
+
+DS_DBUS_SERVICE = 'org.laptop.sugar.DataStore'
+DS_DBUS_INTERFACE = 'org.laptop.sugar.DataStore'
+DS_DBUS_PATH = '/org/laptop/sugar/DataStore'
+
+class ListModel(gtk.GenericTreeModel, gtk.TreeDragSource):
+ __gtype_name__ = 'JournalListModel'
+
+ __gsignals__ = {
+ 'ready': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ 'progress': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ }
+
+ COLUMN_UID = 0
+ COLUMN_FAVORITE = 1
+ COLUMN_ICON = 2
+ COLUMN_ICON_COLOR = 3
+ COLUMN_TITLE = 4
+ COLUMN_DATE = 5
+ COLUMN_PROGRESS = 6
+ COLUMN_BUDDY_1 = 7
+ COLUMN_BUDDY_2 = 8
+ COLUMN_BUDDY_3 = 9
+
+ _COLUMN_TYPES = {COLUMN_UID: str,
+ COLUMN_FAVORITE: bool,
+ COLUMN_ICON: str,
+ COLUMN_ICON_COLOR: object,
+ COLUMN_TITLE: str,
+ COLUMN_DATE: str,
+ COLUMN_PROGRESS: int,
+ COLUMN_BUDDY_1: object,
+ COLUMN_BUDDY_3: object,
+ COLUMN_BUDDY_2: object}
+
+ _PAGE_SIZE = 10
+
+ def __init__(self, query):
+ gobject.GObject.__init__(self)
+
+ self._last_requested_index = None
+ self._cached_row = None
+ self._result_set = model.find(query, ListModel._PAGE_SIZE)
+ self._temp_drag_file_path = None
+
+ # HACK: The view will tell us that it is resizing so the model can
+ # avoid hitting D-Bus and disk.
+ self.view_is_resizing = False
+
+ self._result_set.ready.connect(self.__result_set_ready_cb)
+ self._result_set.progress.connect(self.__result_set_progress_cb)
+
+ def __result_set_ready_cb(self, **kwargs):
+ self.emit('ready')
+
+ def __result_set_progress_cb(self, **kwargs):
+ self.emit('progress')
+
+ def setup(self):
+ self._result_set.setup()
+
+ def stop(self):
+ self._result_set.stop()
+
+ def get_metadata(self, path):
+ return model.get(self[path][ListModel.COLUMN_UID])
+
+ def on_get_n_columns(self):
+ return len(ListModel._COLUMN_TYPES)
+
+ def on_get_column_type(self, index):
+ return ListModel._COLUMN_TYPES[index]
+
+ def on_iter_n_children(self, iterator):
+ if iterator == None:
+ return self._result_set.length
+ else:
+ return 0
+
+ def on_get_value(self, index, column):
+ if self.view_is_resizing:
+ return None
+
+ if index == self._last_requested_index:
+ return self._cached_row[column]
+
+ if index >= self._result_set.length:
+ return None
+
+ self._result_set.seek(index)
+ metadata = self._result_set.read()
+
+ self._last_requested_index = index
+ self._cached_row = []
+ self._cached_row.append(metadata['uid'])
+ self._cached_row.append(metadata.get('keep', '0') == '1')
+ self._cached_row.append(misc.get_icon_name(metadata))
+
+ if misc.is_activity_bundle(metadata):
+ xo_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ else:
+ xo_color = misc.get_icon_color(metadata)
+ self._cached_row.append(xo_color)
+
+ title = gobject.markup_escape_text(metadata.get('title', None))
+ self._cached_row.append('<b>%s</b>' % title)
+
+ timestamp = int(metadata.get('timestamp', 0))
+ self._cached_row.append(util.timestamp_to_elapsed_string(timestamp))
+
+ self._cached_row.append(int(metadata.get('progress', 100)))
+
+ if metadata.get('buddies', ''):
+ buddies = simplejson.loads(metadata['buddies']).values()
+ else:
+ buddies = []
+
+ for n_ in xrange(0, 3):
+ if buddies:
+ nick, color = buddies.pop(0)
+ self._cached_row.append((nick, XoColor(color)))
+ else:
+ self._cached_row.append(None)
+
+ return self._cached_row[column]
+
+ def on_iter_nth_child(self, iterator, n):
+ return n
+
+ def on_get_path(self, iterator):
+ return (iterator)
+
+ def on_get_iter(self, path):
+ return path[0]
+
+ def on_iter_next(self, iterator):
+ if iterator != None:
+ if iterator >= self._result_set.length - 1:
+ return None
+ return iterator + 1
+ return None
+
+ def on_get_flags(self):
+ return gtk.TREE_MODEL_ITERS_PERSIST | gtk.TREE_MODEL_LIST_ONLY
+
+ def on_iter_children(self, iterator):
+ return None
+
+ def on_iter_has_child(self, iterator):
+ return False
+
+ def on_iter_parent(self, iterator):
+ return None
+
+ def do_drag_data_get(self, path, selection):
+ uid = self[path][ListModel.COLUMN_UID]
+ if selection.target == 'text/uri-list':
+ # Get hold of a reference so the temp file doesn't get deleted
+ self._temp_drag_file_path = model.get_file(uid)
+ logging.debug('putting %r in selection', self._temp_drag_file_path)
+ selection.set(selection.target, 8, self._temp_drag_file_path)
+ return True
+ elif selection.target == 'journal-object-id':
+ selection.set(selection.target, 8, uid)
+ return True
+
+ return False
+
diff --git a/shell/src/jarabe/journal/listview.py b/shell/src/jarabe/journal/listview.py
new file mode 100644
index 0000000..9e19f70
--- /dev/null
+++ b/shell/src/jarabe/journal/listview.py
@@ -0,0 +1,641 @@
+# Copyright (C) 2009, Tomeu Vizoso
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+import time
+
+import gobject
+import gtk
+import hippo
+import gconf
+import pango
+
+from sugar.graphics import style
+from sugar.graphics.icon import CanvasIcon, Icon, CellRendererIcon
+from sugar.graphics.xocolor import XoColor
+from sugar import util
+
+from jarabe.journal.listmodel import ListModel
+from jarabe.journal.palettes import ObjectPalette, BuddyPalette
+from jarabe.journal import model
+from jarabe.journal import misc
+
+UPDATE_INTERVAL = 300
+
+MESSAGE_EMPTY_JOURNAL = 0
+MESSAGE_NO_MATCH = 1
+
+class TreeView(gtk.TreeView):
+ __gtype_name__ = 'JournalTreeView'
+
+ def __init__(self):
+ gtk.TreeView.__init__(self)
+ self.set_headers_visible(False)
+
+ def do_size_request(self, requisition):
+ # HACK: We tell the model that the view is just resizing so it can avoid
+ # hitting both D-Bus and disk.
+ tree_model = self.get_model()
+ if tree_model is not None:
+ tree_model.view_is_resizing = True
+ try:
+ gtk.TreeView.do_size_request(self, requisition)
+ finally:
+ if tree_model is not None:
+ tree_model.view_is_resizing = False
+
+class BaseListView(gtk.Bin):
+ __gtype_name__ = 'JournalBaseListView'
+
+ __gsignals__ = {
+ 'clear-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([]))
+ }
+
+ def __init__(self):
+ self._query = {}
+ self._model = None
+ self._progress_bar = None
+ self._last_progress_bar_pulse = None
+ self._scroll_position = 0.
+
+ gobject.GObject.__init__(self)
+
+ self.connect('map', self.__map_cb)
+ self.connect('unrealize', self.__unrealize_cb)
+ self.connect('destroy', self.__destroy_cb)
+
+ self._scrolled_window = gtk.ScrolledWindow()
+ self._scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.add(self._scrolled_window)
+ self._scrolled_window.show()
+
+ self.tree_view = TreeView()
+ selection = self.tree_view.get_selection()
+ selection.set_mode(gtk.SELECTION_NONE)
+ self.tree_view.props.fixed_height_mode = True
+ self.tree_view.modify_base(gtk.STATE_NORMAL,
+ style.COLOR_WHITE.get_gdk_color())
+ self._scrolled_window.add(self.tree_view)
+ self.tree_view.show()
+
+ self.cell_title = None
+ self.cell_icon = None
+ self._title_column = None
+ self.date_column = None
+ self._add_columns()
+
+ self.tree_view.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
+ [('text/uri-list', 0, 0),
+ ('journal-object-id', 0, 0)],
+ gtk.gdk.ACTION_COPY)
+
+ # Auto-update stuff
+ self._fully_obscured = True
+ self._dirty = False
+ self._refresh_idle_handler = None
+ self._update_dates_timer = None
+
+ model.created.connect(self.__model_created_cb)
+ model.updated.connect(self.__model_updated_cb)
+ model.deleted.connect(self.__model_deleted_cb)
+
+ def __model_created_cb(self, sender, **kwargs):
+ self._set_dirty()
+
+ def __model_updated_cb(self, sender, **kwargs):
+ self._set_dirty()
+
+ def __model_deleted_cb(self, sender, **kwargs):
+ self._set_dirty()
+
+ def _add_columns(self):
+ cell_favorite = CellRendererFavorite(self.tree_view)
+ cell_favorite.connect('clicked', self.__favorite_clicked_cb)
+
+ column = gtk.TreeViewColumn()
+ column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED
+ column.props.fixed_width = cell_favorite.props.width
+ column.pack_start(cell_favorite)
+ column.set_cell_data_func(cell_favorite, self.__favorite_set_data_cb)
+ self.tree_view.append_column(column)
+
+ self.cell_icon = CellRendererActivityIcon(self.tree_view)
+
+ column = gtk.TreeViewColumn()
+ column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED
+ column.props.fixed_width = self.cell_icon.props.width
+ column.pack_start(self.cell_icon)
+ column.add_attribute(self.cell_icon, 'file-name', ListModel.COLUMN_ICON)
+ column.add_attribute(self.cell_icon, 'xo-color',
+ ListModel.COLUMN_ICON_COLOR)
+ self.tree_view.append_column(column)
+
+ self.cell_title = gtk.CellRendererText()
+ self.cell_title.props.ellipsize = pango.ELLIPSIZE_MIDDLE
+ self.cell_title.props.ellipsize_set = True
+
+ self._title_column = gtk.TreeViewColumn()
+ self._title_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED
+ self._title_column.props.expand = True
+ self._title_column.props.clickable = True
+ self._title_column.pack_start(self.cell_title)
+ self._title_column.add_attribute(self.cell_title, 'markup',
+ ListModel.COLUMN_TITLE)
+ self.tree_view.append_column(self._title_column)
+
+ buddies_column = gtk.TreeViewColumn()
+ buddies_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED
+ self.tree_view.append_column(buddies_column)
+
+ for column_index in [ListModel.COLUMN_BUDDY_1, ListModel.COLUMN_BUDDY_2,
+ ListModel.COLUMN_BUDDY_3]:
+ cell_icon = CellRendererBuddy(self.tree_view,
+ column_index=column_index)
+ buddies_column.pack_start(cell_icon)
+ buddies_column.props.fixed_width += cell_icon.props.width
+ buddies_column.add_attribute(cell_icon, 'buddy', column_index)
+ buddies_column.set_cell_data_func(cell_icon,
+ self.__buddies_set_data_cb)
+
+ cell_progress = gtk.CellRendererProgress()
+ cell_progress.props.ypad = style.GRID_CELL_SIZE / 4
+ buddies_column.pack_start(cell_progress)
+ buddies_column.add_attribute(cell_progress, 'value',
+ ListModel.COLUMN_PROGRESS)
+ buddies_column.set_cell_data_func(cell_progress,
+ self.__progress_data_cb)
+
+ cell_text = gtk.CellRendererText()
+ cell_text.props.xalign = 1
+
+ # Measure the required width for a date in the form of "10 hours, 10
+ # minutes ago"
+ timestamp = time.time() - 10 * 60 - 10 * 60 * 60
+ date = util.timestamp_to_elapsed_string(timestamp)
+ date_width = self._get_width_for_string(date)
+
+ self.date_column = gtk.TreeViewColumn()
+ self.date_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED
+ self.date_column.props.fixed_width = date_width
+ self.date_column.set_alignment(1)
+ self.date_column.props.resizable = True
+ self.date_column.props.clickable = True
+ self.date_column.pack_start(cell_text)
+ self.date_column.add_attribute(cell_text, 'text', ListModel.COLUMN_DATE)
+ self.tree_view.append_column(self.date_column)
+
+ def _get_width_for_string(self, text):
+ # Add some extra margin
+ text = text + 'aaaaa'
+
+ widget = gtk.Label('')
+ context = widget.get_pango_context()
+ layout = pango.Layout(context)
+ layout.set_text(text)
+ width, height_ = layout.get_size()
+ return pango.PIXELS(width)
+
+ def do_size_allocate(self, allocation):
+ self.allocation = allocation
+ self.child.size_allocate(allocation)
+
+ def do_size_request(self, requisition):
+ requisition.width, requisition.height = self.child.size_request()
+
+ def __destroy_cb(self, widget):
+ if self._model is not None:
+ self._model.stop()
+
+ def __buddies_set_data_cb(self, column, cell, tree_model, tree_iter):
+ progress = tree_model[tree_iter][ListModel.COLUMN_PROGRESS]
+ cell.props.visible = progress >= 100
+
+ def __progress_data_cb(self, column, cell, tree_model, tree_iter):
+ progress = tree_model[tree_iter][ListModel.COLUMN_PROGRESS]
+ cell.props.visible = progress < 100
+
+ def __favorite_set_data_cb(self, column, cell, tree_model, tree_iter):
+ favorite = tree_model[tree_iter][ListModel.COLUMN_FAVORITE]
+ if favorite:
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ cell.props.xo_color = color
+ else:
+ cell.props.xo_color = None
+
+ def __favorite_clicked_cb(self, cell, path):
+ row = self._model[path]
+ metadata = model.get(row[ListModel.COLUMN_UID])
+ if not model.is_editable(metadata):
+ return
+ if metadata.get('keep', 0) == '1':
+ metadata['keep'] = '0'
+ else:
+ metadata['keep'] = '1'
+ model.write(metadata, update_mtime=False)
+
+ def update_with_query(self, query_dict):
+ logging.debug('ListView.update_with_query')
+ self._query = query_dict
+
+ if 'order_by' not in self._query:
+ self._query['order_by'] = ['+timestamp']
+
+ self.refresh()
+
+ def refresh(self):
+ logging.debug('ListView.refresh query %r', self._query)
+ self._stop_progress_bar()
+
+ if self._model is not None:
+ self._model.stop()
+ self._dirty = False
+
+ self._model = ListModel(self._query)
+ self._model.connect('ready', self.__model_ready_cb)
+ self._model.connect('progress', self.__model_progress_cb)
+ self._model.setup()
+
+ def __model_ready_cb(self, tree_model):
+ self._stop_progress_bar()
+
+ self._scroll_position = self.tree_view.props.vadjustment.props.value
+ logging.debug('ListView.__model_ready_cb %r', self._scroll_position)
+
+ if self.tree_view.window is not None:
+ # prevent glitches while later vadjustment setting, see #1235
+ self.tree_view.get_bin_window().hide()
+
+ # Cannot set it up earlier because will try to access the model
+ # and it needs to be ready.
+ self.tree_view.set_model(self._model)
+
+ self.tree_view.props.vadjustment.props.value = self._scroll_position
+ self.tree_view.props.vadjustment.value_changed()
+
+ if self.tree_view.window is not None:
+ # prevent glitches while later vadjustment setting, see #1235
+ self.tree_view.get_bin_window().show()
+
+ if len(tree_model) == 0:
+ if self._is_query_empty():
+ self._show_message(MESSAGE_EMPTY_JOURNAL)
+ else:
+ self._show_message(MESSAGE_NO_MATCH)
+ else:
+ self._clear_message()
+
+ def __map_cb(self, widget):
+ logging.debug('ListView.__map_cb %r', self._scroll_position)
+ self.tree_view.props.vadjustment.props.value = self._scroll_position
+ self.tree_view.props.vadjustment.value_changed()
+
+ def __unrealize_cb(self, widget):
+ self._scroll_position = self.tree_view.props.vadjustment.props.value
+ logging.debug('ListView.__map_cb %r', self._scroll_position)
+
+ is_editable = self._query.get('mountpoints', '') == '/'
+ self.cell_title.props.editable = is_editable
+
+ def _is_query_empty(self):
+ # FIXME: This is a hack, we shouldn't have to update this every time
+ # a new search term is added.
+ if self._query.get('query', '') or self._query.get('mime_type', '') or \
+ self._query.get('keep', '') or self._query.get('mtime', '') or \
+ self._query.get('activity', ''):
+ return False
+ else:
+ return True
+
+ def __model_progress_cb(self, tree_model):
+ if self._progress_bar is None:
+ self._start_progress_bar()
+
+ if time.time() - self._last_progress_bar_pulse > 0.05:
+ self._progress_bar.pulse()
+ self._last_progress_bar_pulse = time.time()
+
+ def _start_progress_bar(self):
+ alignment = gtk.Alignment(xalign=0.5, yalign=0.5, xscale=0.5)
+ self.remove(self.child)
+ self.add(alignment)
+ alignment.show()
+
+ self._progress_bar = gtk.ProgressBar()
+ self._progress_bar.props.pulse_step = 0.01
+ self._last_progress_bar_pulse = time.time()
+ alignment.add(self._progress_bar)
+ self._progress_bar.show()
+
+ def _stop_progress_bar(self):
+ if self._progress_bar is None:
+ return
+ self.remove(self.child)
+ self.add(self._scrolled_window)
+ self._progress_bar = None
+
+ def _show_message(self, message):
+ canvas = hippo.Canvas()
+ self.remove(self.child)
+ self.add(canvas)
+ canvas.show()
+
+ box = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL,
+ background_color=style.COLOR_WHITE.get_int(),
+ yalign=hippo.ALIGNMENT_CENTER,
+ spacing=style.DEFAULT_SPACING,
+ padding_bottom=style.GRID_CELL_SIZE)
+ canvas.set_root(box)
+
+ icon = CanvasIcon(size=style.LARGE_ICON_SIZE,
+ icon_name='activity-journal',
+ stroke_color = style.COLOR_BUTTON_GREY.get_svg(),
+ fill_color = style.COLOR_TRANSPARENT.get_svg())
+ box.append(icon)
+
+ if message == MESSAGE_EMPTY_JOURNAL:
+ text = _('Your Journal is empty')
+ elif message == MESSAGE_NO_MATCH:
+ text = _('No matching entries')
+ else:
+ raise ValueError('Invalid message')
+
+ text = hippo.CanvasText(text=text,
+ xalign=hippo.ALIGNMENT_CENTER,
+ font_desc=style.FONT_BOLD.get_pango_desc(),
+ color = style.COLOR_BUTTON_GREY.get_int())
+ box.append(text)
+
+ if message == MESSAGE_NO_MATCH:
+ button = gtk.Button(label=_('Clear search'))
+ button.connect('clicked', self.__clear_button_clicked_cb)
+ button.props.image = Icon(icon_name='dialog-cancel',
+ icon_size=gtk.ICON_SIZE_BUTTON)
+ canvas_button = hippo.CanvasWidget(widget=button,
+ xalign=hippo.ALIGNMENT_CENTER)
+ box.append(canvas_button)
+
+ def __clear_button_clicked_cb(self, button):
+ self.emit('clear-clicked')
+
+ def _clear_message(self):
+ if self.child == self._scrolled_window:
+ return
+ self.remove(self.child)
+ self.add(self._scrolled_window)
+ self._scrolled_window.show()
+
+ def update_dates(self):
+ if not self.tree_view.flags() & gtk.REALIZED:
+ return
+ visible_range = self.tree_view.get_visible_range()
+ if visible_range is None:
+ return
+
+ logging.debug('ListView.update_dates')
+
+ path, end_path = visible_range
+ tree_model = self.tree_view.get_model()
+
+ while True:
+ x, y, width, height = self.tree_view.get_cell_area(path,
+ self.date_column)
+ x, y = self.tree_view.convert_tree_to_widget_coords(x, y)
+ self.tree_view.queue_draw_area(x, y, width, height)
+ if path == end_path:
+ break
+ else:
+ next_iter = tree_model.iter_next(tree_model.get_iter(path))
+ path = tree_model.get_path(next_iter)
+
+ def _set_dirty(self):
+ if self._fully_obscured:
+ self._dirty = True
+ else:
+ self.refresh()
+
+ def set_is_visible(self, visible):
+ if visible != self._fully_obscured:
+ return
+
+ logging.debug('canvas_visibility_notify_event_cb %r', visible)
+ if visible:
+ self._fully_obscured = False
+ if self._dirty:
+ self.refresh()
+ if self._update_dates_timer is None:
+ logging.debug('Adding date updating timer')
+ self._update_dates_timer = \
+ gobject.timeout_add_seconds(UPDATE_INTERVAL,
+ self.__update_dates_timer_cb)
+ else:
+ self._fully_obscured = True
+ if self._update_dates_timer is not None:
+ logging.debug('Remove date updating timer')
+ gobject.source_remove(self._update_dates_timer)
+ self._update_dates_timer = None
+
+ def __update_dates_timer_cb(self):
+ self.update_dates()
+ return True
+
+class ListView(BaseListView):
+ __gtype_name__ = 'JournalListView'
+
+ __gsignals__ = {
+ 'detail-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([object]))
+ }
+
+ def __init__(self):
+ BaseListView.__init__(self)
+ self._is_dragging = False
+
+ self.tree_view.connect('drag-begin', self.__drag_begin_cb)
+ self.tree_view.connect('button-release-event',
+ self.__button_release_event_cb)
+
+ self.cell_title.connect('edited', self.__cell_title_edited_cb)
+ self.cell_title.connect('editing-canceled', self.__editing_canceled_cb)
+
+ self.cell_icon.connect('clicked', self.__icon_clicked_cb)
+ self.cell_icon.connect('detail-clicked', self.__detail_clicked_cb)
+
+ cell_detail = CellRendererDetail(self.tree_view)
+ cell_detail.connect('clicked', self.__detail_cell_clicked_cb)
+
+ column = gtk.TreeViewColumn()
+ column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED
+ column.props.fixed_width = cell_detail.props.width
+ column.pack_start(cell_detail)
+ self.tree_view.append_column(column)
+
+ def __drag_begin_cb(self, widget, drag_context):
+ self._is_dragging = True
+
+ def __button_release_event_cb(self, tree_view, event):
+ try:
+ if self._is_dragging:
+ return
+ finally:
+ self._is_dragging = False
+
+ pos = tree_view.get_path_at_pos(int(event.x), int(event.y))
+ if pos is None:
+ return
+
+ path, column, x_, y_ = pos
+ if column != self._title_column:
+ return
+
+ row = self.tree_view.get_model()[path]
+ metadata = model.get(row[ListModel.COLUMN_UID])
+ self.cell_title.props.editable = model.is_editable(metadata)
+
+ tree_view.set_cursor_on_cell(path, column, start_editing=True)
+
+ def __detail_cell_clicked_cb(self, cell, path):
+ row = self.tree_view.get_model()[path]
+ self.emit('detail-clicked', row[ListModel.COLUMN_UID])
+
+ def __detail_clicked_cb(self, cell, uid):
+ self.emit('detail-clicked', uid)
+
+ def __icon_clicked_cb(self, cell, path):
+ row = self.tree_view.get_model()[path]
+ metadata = model.get(row[ListModel.COLUMN_UID])
+ misc.resume(metadata)
+
+ def __cell_title_edited_cb(self, cell, path, new_text):
+ row = self._model[path]
+ metadata = model.get(row[ListModel.COLUMN_UID])
+ metadata['title'] = new_text
+ model.write(metadata, update_mtime=False)
+ self.cell_title.props.editable = False
+
+ def __editing_canceled_cb(self, cell):
+ self.cell_title.props.editable = False
+
+class CellRendererFavorite(CellRendererIcon):
+ __gtype_name__ = 'JournalCellRendererFavorite'
+
+ def __init__(self, tree_view):
+ CellRendererIcon.__init__(self, tree_view)
+
+ self.props.width = style.GRID_CELL_SIZE
+ self.props.height = style.GRID_CELL_SIZE
+ self.props.size = style.SMALL_ICON_SIZE
+ self.props.icon_name = 'emblem-favorite'
+ self.props.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
+ self.props.prelit_stroke_color = style.COLOR_BUTTON_GREY.get_svg()
+ self.props.prelit_fill_color = style.COLOR_BUTTON_GREY.get_svg()
+
+class CellRendererDetail(CellRendererIcon):
+ __gtype_name__ = 'JournalCellRendererDetail'
+
+ def __init__(self, tree_view):
+ CellRendererIcon.__init__(self, tree_view)
+
+ self.props.width = style.GRID_CELL_SIZE
+ self.props.height = style.GRID_CELL_SIZE
+ self.props.size = style.SMALL_ICON_SIZE
+ self.props.icon_name = 'go-right'
+ self.props.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
+ self.props.stroke_color = style.COLOR_TRANSPARENT.get_svg()
+ self.props.fill_color = style.COLOR_BUTTON_GREY.get_svg()
+ self.props.prelit_stroke_color = style.COLOR_TRANSPARENT.get_svg()
+ self.props.prelit_fill_color = style.COLOR_BLACK.get_svg()
+
+class CellRendererActivityIcon(CellRendererIcon):
+ __gtype_name__ = 'JournalCellRendererActivityIcon'
+
+ __gsignals__ = {
+ 'detail-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ }
+
+ def __init__(self, tree_view):
+ self._show_palette = True
+
+ CellRendererIcon.__init__(self, tree_view)
+
+ self.props.width = style.GRID_CELL_SIZE
+ self.props.height = style.GRID_CELL_SIZE
+ self.props.size = style.STANDARD_ICON_SIZE
+ self.props.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
+
+ self.tree_view = tree_view
+
+ def create_palette(self):
+ if not self._show_palette:
+ return None
+
+ tree_model = self.tree_view.get_model()
+ metadata = tree_model.get_metadata(self.props.palette_invoker.path)
+
+ palette = ObjectPalette(metadata, detail=True)
+ palette.connect('detail-clicked',
+ self.__detail_clicked_cb)
+ return palette
+
+ def __detail_clicked_cb(self, palette, uid):
+ self.emit('detail-clicked', uid)
+
+ def set_show_palette(self, show_palette):
+ self._show_palette = show_palette
+
+ show_palette = gobject.property(type=bool, default=True,
+ setter=set_show_palette)
+
+class CellRendererBuddy(CellRendererIcon):
+ __gtype_name__ = 'JournalCellRendererBuddy'
+
+ def __init__(self, tree_view, column_index):
+ CellRendererIcon.__init__(self, tree_view)
+
+ self.props.width = style.STANDARD_ICON_SIZE
+ self.props.height = style.STANDARD_ICON_SIZE
+ self.props.size = style.STANDARD_ICON_SIZE
+ self.props.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
+
+ self.tree_view = tree_view
+ self._model_column_index = column_index
+
+ def create_palette(self):
+ tree_model = self.tree_view.get_model()
+ row = tree_model[self.props.palette_invoker.path]
+
+ if row[self._model_column_index] is not None:
+ nick, xo_color = row[self._model_column_index]
+ return BuddyPalette((nick, xo_color.to_string()))
+ else:
+ return None
+
+ def set_buddy(self, buddy):
+ if buddy is None:
+ self.props.icon_name = None
+ else:
+ nick_, xo_color = buddy
+ self.props.icon_name = 'computer-xo'
+ self.props.xo_color = xo_color
+
+ buddy = gobject.property(type=object, setter=set_buddy)
+
diff --git a/shell/src/jarabe/journal/misc.py b/shell/src/jarabe/journal/misc.py
new file mode 100644
index 0000000..657b60e
--- /dev/null
+++ b/shell/src/jarabe/journal/misc.py
@@ -0,0 +1,262 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import time
+import os
+from gettext import gettext as _
+
+import gio
+import gconf
+import gtk
+
+from sugar.activity import activityfactory
+from sugar.activity.activityhandle import ActivityHandle
+from sugar.graphics.icon import get_icon_file_name
+from sugar.graphics.xocolor import XoColor
+from sugar import mime
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.bundle.contentbundle import ContentBundle
+from sugar import util
+
+from jarabe.view import launcher
+from jarabe.model import bundleregistry, shell
+from jarabe.journal.journalentrybundle import JournalEntryBundle
+from jarabe.journal import model
+
+def _get_icon_for_mime(mime_type):
+ generic_types = mime.get_all_generic_types()
+ for generic_type in generic_types:
+ if mime_type in generic_type.mime_types:
+ file_name = get_icon_file_name(generic_type.icon)
+ if file_name is not None:
+ return file_name
+
+ icons = gio.content_type_get_icon(mime_type)
+ logging.debug('icons for this file: %r', icons.props.names)
+ for icon_name in icons.props.names:
+ file_name = get_icon_file_name(icon_name)
+ if file_name is not None:
+ return file_name
+
+def get_icon_name(metadata):
+ file_name = None
+
+ bundle_id = metadata.get('activity', '')
+ if not bundle_id:
+ bundle_id = metadata.get('bundle_id', '')
+
+ if bundle_id:
+ activity_info = bundleregistry.get_registry().get_bundle(bundle_id)
+ if activity_info:
+ file_name = activity_info.get_icon()
+
+ if file_name is None and is_activity_bundle(metadata):
+ file_path = model.get_file(metadata['uid'])
+ if file_path is not None and os.path.exists(file_path):
+ try:
+ bundle = ActivityBundle(file_path)
+ file_name = bundle.get_icon()
+ except Exception:
+ logging.exception('Could not read bundle')
+
+ if file_name is None:
+ file_name = _get_icon_for_mime(metadata.get('mime_type', ''))
+
+ if file_name is None:
+ file_name = get_icon_file_name('application-octet-stream')
+
+ return file_name
+
+def get_date(metadata):
+ """ Convert from a string in iso format to a more human-like format. """
+ if metadata.has_key('timestamp'):
+ timestamp = float(metadata['timestamp'])
+ return util.timestamp_to_elapsed_string(timestamp)
+ elif metadata.has_key('mtime'):
+ ti = time.strptime(metadata['mtime'], "%Y-%m-%dT%H:%M:%S")
+ return util.timestamp_to_elapsed_string(time.mktime(ti))
+ else:
+ return _('No date')
+
+def get_bundle(metadata):
+ try:
+ if is_activity_bundle(metadata):
+ file_path = util.TempFilePath(model.get_file(metadata['uid']))
+ if not os.path.exists(file_path):
+ logging.warning('Invalid path: %r', file_path)
+ return None
+ return ActivityBundle(file_path)
+
+ elif is_content_bundle(metadata):
+ file_path = util.TempFilePath(model.get_file(metadata['uid']))
+ if not os.path.exists(file_path):
+ logging.warning('Invalid path: %r', file_path)
+ return None
+ return ContentBundle(file_path)
+
+ elif is_journal_bundle(metadata):
+ file_path = util.TempFilePath(model.get_file(metadata['uid']))
+ if not os.path.exists(file_path):
+ logging.warning('Invalid path: %r', file_path)
+ return None
+ return JournalEntryBundle(file_path)
+ else:
+ return None
+ except Exception:
+ logging.exception('Incorrect bundle')
+ return None
+
+def _get_activities_for_mime(mime_type):
+ registry = bundleregistry.get_registry()
+ result = registry.get_activities_for_type(mime_type)
+ if not result:
+ for parent_mime in mime.get_mime_parents(mime_type):
+ for activity in registry.get_activities_for_type(parent_mime):
+ if activity not in result:
+ result.append(activity)
+ return result
+
+def get_activities(metadata):
+ activities = []
+
+ bundle_id = metadata.get('activity', '')
+ if bundle_id:
+ activity_info = bundleregistry.get_registry().get_bundle(bundle_id)
+ if activity_info:
+ activities.append(activity_info)
+
+ mime_type = metadata.get('mime_type', '')
+ if mime_type:
+ activities_info = _get_activities_for_mime(mime_type)
+ for activity_info in activities_info:
+ if activity_info not in activities:
+ activities.append(activity_info)
+
+ return activities
+
+def resume(metadata, bundle_id=None):
+ registry = bundleregistry.get_registry()
+
+ if is_activity_bundle(metadata) and bundle_id is None:
+
+ logging.debug('Creating activity bundle')
+
+ file_path = model.get_file(metadata['uid'])
+ bundle = ActivityBundle(file_path)
+ if not registry.is_installed(bundle):
+ logging.debug('Installing activity bundle')
+ registry.install(bundle)
+ else:
+ logging.debug('Upgrading activity bundle')
+ registry.upgrade(bundle)
+
+ logging.debug('activityfactory.creating bundle with id %r',
+ bundle.get_bundle_id())
+ installed_bundle = registry.get_bundle(bundle.get_bundle_id())
+ if installed_bundle:
+ launch(installed_bundle)
+ else:
+ logging.error('Bundle %r is not installed.',
+ bundle.get_bundle_id())
+
+ elif is_content_bundle(metadata) and bundle_id is None:
+
+ logging.debug('Creating content bundle')
+
+ file_path = model.get_file(metadata['uid'])
+ bundle = ContentBundle(file_path)
+ if not bundle.is_installed():
+ logging.debug('Installing content bundle')
+ bundle.install()
+
+ activities = _get_activities_for_mime('text/html')
+ if len(activities) == 0:
+ logging.warning('No activity can open HTML content bundles')
+ return
+
+ uri = bundle.get_start_uri()
+ logging.debug('activityfactory.creating with uri %s', uri)
+
+ activity_bundle = registry.get_bundle(activities[0].get_bundle_id())
+ launch(activity_bundle, uri=uri)
+ else:
+ activity_id = metadata.get('activity_id', '')
+
+ if bundle_id is None:
+ activities = get_activities(metadata)
+ if not activities:
+ logging.warning('No activity can open this object, %s.',
+ metadata.get('mime_type', None))
+ return
+ bundle_id = activities[0].get_bundle_id()
+
+ bundle = registry.get_bundle(bundle_id)
+
+
+ if metadata.get('mountpoint', '/') == '/':
+ object_id = metadata['uid']
+ else:
+ object_id = model.copy(metadata, '/')
+
+ launch(bundle, activity_id=activity_id, object_id=object_id,
+ color=get_icon_color(metadata))
+
+def launch(bundle, activity_id=None, object_id=None, uri=None, color=None,
+ invited=False):
+ if activity_id is None:
+ activity_id = activityfactory.create_activity_id()
+
+ logging.debug('launch bundle_id=%s activity_id=%s object_id=%s uri=%s',
+ bundle.get_bundle_id(), activity_id, object_id, uri)
+
+ shell_model = shell.get_model()
+ activity = shell_model.get_activity_by_id(activity_id)
+ if activity is not None:
+ logging.debug('re-launch %r', activity.get_window())
+ activity.get_window().activate(gtk.get_current_event_time())
+ return
+
+ if color is None:
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ launcher.add_launcher(activity_id, bundle.get_icon(), color)
+ activity_handle = ActivityHandle(activity_id=activity_id,
+ object_id=object_id, uri=uri, invited=invited)
+ activityfactory.create(bundle, activity_handle)
+
+def is_activity_bundle(metadata):
+ mime_type = metadata.get('mime_type', '')
+ return mime_type == ActivityBundle.MIME_TYPE or \
+ mime_type == ActivityBundle.DEPRECATED_MIME_TYPE
+
+def is_content_bundle(metadata):
+ return metadata.get('mime_type', '') == ContentBundle.MIME_TYPE
+
+def is_journal_bundle(metadata):
+ return metadata.get('mime_type', '') == JournalEntryBundle.MIME_TYPE
+
+def is_bundle(metadata):
+ return is_activity_bundle(metadata) or is_content_bundle(metadata) or \
+ is_journal_bundle(metadata)
+
+def get_icon_color(metadata):
+ if metadata is None or not 'icon-color' in metadata:
+ client = gconf.client_get_default()
+ return XoColor(client.get_string('/desktop/sugar/user/color'))
+ else:
+ return XoColor(metadata['icon-color'])
diff --git a/shell/src/jarabe/journal/modalalert.py b/shell/src/jarabe/journal/modalalert.py
new file mode 100644
index 0000000..c7c6a0a
--- /dev/null
+++ b/shell/src/jarabe/journal/modalalert.py
@@ -0,0 +1,97 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+from gettext import gettext as _
+import gconf
+
+from sugar.graphics.icon import Icon
+from sugar.graphics import style
+from sugar.graphics.xocolor import XoColor
+
+class ModalAlert(gtk.Window):
+
+ __gtype_name__ = 'SugarModalAlert'
+
+ def __init__(self):
+ gtk.Window.__init__(self)
+
+ self.set_border_width(style.LINE_WIDTH)
+ offset = style.GRID_CELL_SIZE
+ width = gtk.gdk.screen_width() - offset * 2
+ height = gtk.gdk.screen_height() - offset * 2
+ self.set_size_request(width, height)
+ self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.set_decorated(False)
+ self.set_resizable(False)
+ self.set_modal(True)
+
+ self._main_view = gtk.EventBox()
+ self._vbox = gtk.VBox()
+ self._vbox.set_spacing(style.DEFAULT_SPACING)
+ self._vbox.set_border_width(style.GRID_CELL_SIZE * 2)
+ self._main_view.modify_bg(gtk.STATE_NORMAL,
+ style.COLOR_BLACK.get_gdk_color())
+ self._main_view.add(self._vbox)
+ self._vbox.show()
+
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ icon = Icon(icon_name='activity-journal',
+ pixel_size=style.XLARGE_ICON_SIZE,
+ xo_color=color)
+ self._vbox.pack_start(icon, False)
+ icon.show()
+
+ self._title = gtk.Label()
+ self._title.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_WHITE.get_gdk_color())
+ self._title.set_markup('<b>%s</b>' % _('Your Journal is full'))
+ self._vbox.pack_start(self._title, False)
+ self._title.show()
+
+ self._message = gtk.Label(_('Please delete some old Journal'
+ ' entries to make space for new ones.'))
+ self._message.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_WHITE.get_gdk_color())
+ self._vbox.pack_start(self._message, False)
+ self._message.show()
+
+ alignment = gtk.Alignment(xalign=0.5, yalign=0.5)
+ self._vbox.pack_start(alignment, expand=False)
+ alignment.show()
+
+ self._show_journal = gtk.Button()
+ self._show_journal.set_label(_('Show Journal'))
+ alignment.add(self._show_journal)
+ self._show_journal.show()
+ self._show_journal.connect('clicked', self.__show_journal_cb)
+
+ self.add(self._main_view)
+ self._main_view.show()
+
+ self.connect("realize", self.__realize_cb)
+
+ def __realize_cb(self, widget):
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.window.set_accept_focus(True)
+
+ def __show_journal_cb(self, button):
+ '''The opener will listen on the destroy signal
+ '''
+ self.destroy()
+
diff --git a/shell/src/jarabe/journal/model.py b/shell/src/jarabe/journal/model.py
new file mode 100644
index 0000000..ffc62e0
--- /dev/null
+++ b/shell/src/jarabe/journal/model.py
@@ -0,0 +1,541 @@
+# Copyright (C) 2007-2008, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import os
+from datetime import datetime
+import time
+import shutil
+from stat import S_IFMT, S_IFDIR, S_IFREG
+import re
+
+import gobject
+import dbus
+import gconf
+import gio
+
+from sugar import dispatch
+from sugar import mime
+from sugar import util
+
+DS_DBUS_SERVICE = 'org.laptop.sugar.DataStore'
+DS_DBUS_INTERFACE = 'org.laptop.sugar.DataStore'
+DS_DBUS_PATH = '/org/laptop/sugar/DataStore'
+
+# Properties the journal cares about.
+PROPERTIES = ['uid', 'title', 'mtime', 'timestamp', 'keep', 'buddies',
+ 'icon-color', 'mime_type', 'progress', 'activity', 'mountpoint',
+ 'activity_id', 'bundle_id']
+
+MIN_PAGES_TO_CACHE = 3
+MAX_PAGES_TO_CACHE = 5
+
+class _Cache(object):
+
+ __gtype_name__ = 'model_Cache'
+
+ def __init__(self, entries=None):
+ self._array = []
+ if entries is not None:
+ self.append_all(entries)
+
+ def prepend_all(self, entries):
+ self._array[0:0] = entries
+
+ def append_all(self, entries):
+ self._array += entries
+
+ def __len__(self):
+ return len(self._array)
+
+ def __getitem__(self, key):
+ return self._array[key]
+
+ def __delitem__(self, key):
+ del self._array[key]
+
+
+class BaseResultSet(object):
+ """Encapsulates the result of a query
+ """
+
+ def __init__(self, query, page_size):
+ self._total_count = -1
+ self._position = -1
+ self._query = query
+ self._page_size = page_size
+
+ self._offset = 0
+ self._cache = _Cache()
+
+ self.ready = dispatch.Signal()
+ self.progress = dispatch.Signal()
+
+ def setup(self):
+ self.ready.send(self)
+
+ def stop(self):
+ pass
+
+ def get_length(self):
+ if self._total_count == -1:
+ query = self._query.copy()
+ query['limit'] = self._page_size * MIN_PAGES_TO_CACHE
+ entries, self._total_count = self.find(query)
+ self._cache.append_all(entries)
+ self._offset = 0
+ return self._total_count
+
+ length = property(get_length)
+
+ def find(self, query):
+ raise NotImplementedError()
+
+ def seek(self, position):
+ self._position = position
+
+ def read(self):
+ logging.debug('ResultSet.read position: %r', self._position)
+
+ if self._position == -1:
+ self.seek(0)
+
+ if self._position < self._offset:
+ remaining_forward_entries = 0
+ else:
+ remaining_forward_entries = self._offset + len(self._cache) - \
+ self._position
+
+ if self._position > self._offset + len(self._cache):
+ remaining_backwards_entries = 0
+ else:
+ remaining_backwards_entries = self._position - self._offset
+
+ last_cached_entry = self._offset + len(self._cache)
+
+ if remaining_forward_entries <= 0 and remaining_backwards_entries <= 0:
+
+ # Total cache miss: remake it
+ limit = self._page_size * MIN_PAGES_TO_CACHE
+ offset = max(0, self._position - limit / 2)
+ logging.debug('remaking cache, offset: %r limit: %r', offset,
+ limit)
+ query = self._query.copy()
+ query['limit'] = limit
+ query['offset'] = offset
+ entries, self._total_count = self.find(query)
+
+ del self._cache[:]
+ self._cache.append_all(entries)
+ self._offset = offset
+
+ elif remaining_forward_entries <= 0 and remaining_backwards_entries > 0:
+
+ # Add one page to the end of cache
+ logging.debug('appending one more page, offset: %r',
+ last_cached_entry)
+ query = self._query.copy()
+ query['limit'] = self._page_size
+ query['offset'] = last_cached_entry
+ entries, self._total_count = self.find(query)
+
+ # update cache
+ self._cache.append_all(entries)
+
+ # apply the cache limit
+ cache_limit = self._page_size * MAX_PAGES_TO_CACHE
+ objects_excess = len(self._cache) - cache_limit
+ if objects_excess > 0:
+ self._offset += objects_excess
+ del self._cache[:objects_excess]
+
+ elif remaining_forward_entries > 0 and \
+ remaining_backwards_entries <= 0 and self._offset > 0:
+
+ # Add one page to the beginning of cache
+ limit = min(self._offset, self._page_size)
+ self._offset = max(0, self._offset - limit)
+
+ logging.debug('prepending one more page, offset: %r limit: %r',
+ self._offset, limit)
+ query = self._query.copy()
+ query['limit'] = limit
+ query['offset'] = self._offset
+ entries, self._total_count = self.find(query)
+
+ # update cache
+ self._cache.prepend_all(entries)
+
+ # apply the cache limit
+ cache_limit = self._page_size * MAX_PAGES_TO_CACHE
+ objects_excess = len(self._cache) - cache_limit
+ if objects_excess > 0:
+ del self._cache[-objects_excess:]
+ else:
+ logging.debug('cache hit and no need to grow the cache')
+
+ return self._cache[self._position - self._offset]
+
+class DatastoreResultSet(BaseResultSet):
+ """Encapsulates the result of a query on the datastore
+ """
+ def __init__(self, query, page_size):
+
+ if query.get('query', '') and not query['query'].startswith('"'):
+ query_text = ''
+ words = query['query'].split(' ')
+ for word in words:
+ if word:
+ if query_text:
+ query_text += ' '
+ query_text += word + '*'
+
+ query['query'] = query_text
+
+ BaseResultSet.__init__(self, query, page_size)
+
+ def find(self, query):
+ entries, total_count = _get_datastore().find(query, PROPERTIES,
+ byte_arrays=True)
+
+ for entry in entries:
+ entry['mountpoint'] = '/'
+
+ return entries, total_count
+
+class InplaceResultSet(BaseResultSet):
+ """Encapsulates the result of a query on a mount point
+ """
+ def __init__(self, query, page_size, mount_point):
+ BaseResultSet.__init__(self, query, page_size)
+ self._mount_point = mount_point
+ self._file_list = None
+ self._pending_directories = 0
+ self._stopped = False
+
+ query_text = query.get('query', '')
+ if query_text.startswith('"') and query_text.endswith('"'):
+ self._regex = re.compile('*%s*' % query_text.strip(['"']))
+ elif query_text:
+ expression = ''
+ for word in query_text.split(' '):
+ expression += '(?=.*%s.*)' % word
+ self._regex = re.compile(expression, re.IGNORECASE)
+ else:
+ self._regex = None
+
+ if query.get('timestamp', ''):
+ self._date_start = int(query['timestamp']['start'])
+ self._date_end = int(query['timestamp']['end'])
+ else:
+ self._date_start = None
+ self._date_end = None
+
+ self._mime_types = query.get('mime_type', [])
+
+ def setup(self):
+ self._file_list = []
+ self._recurse_dir(self._mount_point)
+
+ def stop(self):
+ self._stopped = True
+
+ def setup_ready(self):
+ self._file_list.sort(lambda a, b: b[2] - a[2])
+ self.ready.send(self)
+
+ def find(self, query):
+ if self._file_list is None:
+ raise ValueError('Need to call setup() first')
+
+ if self._stopped:
+ raise ValueError('InplaceResultSet already stopped')
+
+ t = time.time()
+
+ offset = int(query.get('offset', 0))
+ limit = int(query.get('limit', len(self._file_list)))
+ total_count = len(self._file_list)
+
+ files = self._file_list[offset:offset + limit]
+
+ entries = []
+ for file_path, stat, mtime_ in files:
+ metadata = _get_file_metadata(file_path, stat)
+ metadata['mountpoint'] = self._mount_point
+ entries.append(metadata)
+
+ logging.debug('InplaceResultSet.find took %f s.', time.time() - t)
+
+ return entries, total_count
+
+ def _recurse_dir(self, dir_path):
+ self._pending_directories += 1
+ gobject.idle_add(self._idle_recurse_dir, dir_path)
+
+ def _idle_recurse_dir(self, dir_path):
+ try:
+ self._real_recurse_dir(dir_path)
+ finally:
+ self._pending_directories -= 1
+ if self._pending_directories == 0:
+ self.setup_ready()
+
+ def _real_recurse_dir(self, dir_path):
+ if self._stopped:
+ return
+
+ try:
+ dirs = os.listdir(dir_path)
+ except Exception:
+ logging.exception('Error reading directory %r', dir_path)
+ dirs = []
+
+ for entry in dirs:
+ if entry.startswith('.'):
+ continue
+ full_path = dir_path + '/' + entry
+ try:
+ stat = os.stat(full_path)
+ if S_IFMT(stat.st_mode) == S_IFDIR:
+ self._recurse_dir(full_path)
+
+ elif S_IFMT(stat.st_mode) == S_IFREG:
+ add_to_list = True
+
+ if self._regex is not None and \
+ not self._regex.match(full_path):
+ add_to_list = False
+
+ if None not in [self._date_start, self._date_end] and \
+ (stat.st_mtime < self._date_start or
+ stat.st_mtime > self._date_end):
+ add_to_list = False
+
+ if self._mime_types:
+ mime_type = gio.content_type_guess(filename=full_path)
+ if mime_type not in self._mime_types:
+ add_to_list = False
+
+ if add_to_list:
+ file_info = (full_path, stat, int(stat.st_mtime))
+ self._file_list.append(file_info)
+
+ self.progress.send(self)
+
+ except Exception:
+ logging.exception('Error reading file %r', full_path)
+
+def _get_file_metadata(path, stat):
+ client = gconf.client_get_default()
+ return {'uid': path,
+ 'title': os.path.basename(path),
+ 'timestamp': stat.st_mtime,
+ 'mime_type': gio.content_type_guess(filename=path),
+ 'activity': '',
+ 'activity_id': '',
+ 'icon-color': client.get_string('/desktop/sugar/user/color'),
+ 'description': path}
+
+_datastore = None
+def _get_datastore():
+ global _datastore
+ if _datastore is None:
+ bus = dbus.SessionBus()
+ remote_object = bus.get_object(DS_DBUS_SERVICE, DS_DBUS_PATH)
+ _datastore = dbus.Interface(remote_object, DS_DBUS_INTERFACE)
+
+ _datastore.connect_to_signal('Created', _datastore_created_cb)
+ _datastore.connect_to_signal('Updated', _datastore_updated_cb)
+ _datastore.connect_to_signal('Deleted', _datastore_deleted_cb)
+
+ return _datastore
+
+def _datastore_created_cb(object_id):
+ created.send(None, object_id=object_id)
+
+def _datastore_updated_cb(object_id):
+ updated.send(None, object_id=object_id)
+
+def _datastore_deleted_cb(object_id):
+ deleted.send(None, object_id=object_id)
+
+def find(query_, page_size):
+ """Returns a ResultSet
+ """
+ query = query_.copy()
+
+ mount_points = query.pop('mountpoints', ['/'])
+ if mount_points is None or len(mount_points) != 1:
+ raise ValueError('Exactly one mount point must be specified')
+
+ if mount_points[0] == '/':
+ return DatastoreResultSet(query, page_size)
+ else:
+ return InplaceResultSet(query, page_size, mount_points[0])
+
+def _get_mount_point(path):
+ dir_path = os.path.dirname(path)
+ while True:
+ if os.path.ismount(dir_path):
+ return dir_path
+ else:
+ dir_path = dir_path.rsplit(os.sep, 1)[0]
+
+def get(object_id):
+ """Returns the metadata for an object
+ """
+ if os.path.exists(object_id):
+ stat = os.stat(object_id)
+ metadata = _get_file_metadata(object_id, stat)
+ metadata['mountpoint'] = _get_mount_point(object_id)
+ else:
+ metadata = _get_datastore().get_properties(object_id, byte_arrays=True)
+ metadata['mountpoint'] = '/'
+ return metadata
+
+def get_file(object_id):
+ """Returns the file for an object
+ """
+ if os.path.exists(object_id):
+ logging.debug('get_file asked for file with path %r', object_id)
+ return object_id
+ else:
+ logging.debug('get_file asked for entry with id %r', object_id)
+ file_path = _get_datastore().get_filename(object_id)
+ if file_path:
+ return util.TempFilePath(file_path)
+ else:
+ return None
+
+def get_file_size(object_id):
+ """Return the file size for an object
+ """
+ logging.debug('get_file_size %r', object_id)
+ if os.path.exists(object_id):
+ return os.stat(object_id).st_size
+
+ file_path = _get_datastore().get_filename(object_id)
+ if file_path:
+ size = os.stat(file_path).st_size
+ os.remove(file_path)
+ return size
+
+ return 0
+
+def get_unique_values(key):
+ """Returns a list with the different values a property has taken
+ """
+ empty_dict = dbus.Dictionary({}, signature='ss')
+ return _get_datastore().get_uniquevaluesfor(key, empty_dict)
+
+def delete(object_id):
+ """Removes an object from persistent storage
+ """
+ if os.path.exists(object_id):
+ os.unlink(object_id)
+ deleted.send(None, object_id=object_id)
+ else:
+ _get_datastore().delete(object_id)
+
+def copy(metadata, mount_point):
+ """Copies an object to another mount point
+ """
+ metadata = get(metadata['uid'])
+ file_path = get_file(metadata['uid'])
+
+ metadata['mountpoint'] = mount_point
+ del metadata['uid']
+
+ return write(metadata, file_path, transfer_ownership=False)
+
+def write(metadata, file_path='', update_mtime=True, transfer_ownership=True):
+ """Creates or updates an entry for that id
+ """
+ logging.debug('model.write %r %r %r', metadata.get('uid', ''), file_path,
+ update_mtime)
+ if update_mtime:
+ metadata['mtime'] = datetime.now().isoformat()
+ metadata['timestamp'] = int(time.time())
+
+ if metadata.get('mountpoint', '/') == '/':
+ if metadata.get('uid', ''):
+ object_id = _get_datastore().update(metadata['uid'],
+ dbus.Dictionary(metadata),
+ file_path,
+ transfer_ownership)
+ else:
+ object_id = _get_datastore().create(dbus.Dictionary(metadata),
+ file_path,
+ transfer_ownership)
+ else:
+ if not os.path.exists(file_path):
+ raise ValueError('Entries without a file cannot be copied to '
+ 'removable devices')
+
+ file_name = _get_file_name(metadata['title'], metadata['mime_type'])
+ file_name = _get_unique_file_name(metadata['mountpoint'], file_name)
+
+ destination_path = os.path.join(metadata['mountpoint'], file_name)
+ shutil.copy(file_path, destination_path)
+ object_id = destination_path
+ created.send(None, object_id=object_id)
+
+ return object_id
+
+def _get_file_name(title, mime_type):
+ file_name = title
+
+ extension = mime.get_primary_extension(mime_type)
+ if extension is not None and extension:
+ extension = '.' + extension
+ if not file_name.endswith(extension):
+ file_name += extension
+
+ # Invalid characters in VFAT filenames. From
+ # http://en.wikipedia.org/wiki/File_Allocation_Table
+ invalid_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\x7F']
+ invalid_chars.extend([chr(x) for x in range(0, 32)])
+ for char in invalid_chars:
+ file_name = file_name.replace(char, '_')
+
+ # FAT limit is 255, leave some space for uniqueness
+ max_len = 250
+ if len(file_name) > max_len:
+ name, extension = os.path.splitext(file_name)
+ file_name = name[0:max_len - len(extension)] + extension
+
+ return file_name
+
+def _get_unique_file_name(mount_point, file_name):
+ if os.path.exists(os.path.join(mount_point, file_name)):
+ i = 1
+ while len(file_name) <= 255:
+ name, extension = os.path.splitext(file_name)
+ file_name = name + '_' + str(i) + extension
+ if not os.path.exists(os.path.join(mount_point, file_name)):
+ break
+ i += 1
+
+ return file_name
+
+def is_editable(metadata):
+ mountpoint = metadata.get('mountpoint', '/')
+ return mountpoint == '/'
+
+created = dispatch.Signal()
+updated = dispatch.Signal()
+deleted = dispatch.Signal()
diff --git a/shell/src/jarabe/journal/objectchooser.py b/shell/src/jarabe/journal/objectchooser.py
new file mode 100644
index 0000000..49af3e6
--- /dev/null
+++ b/shell/src/jarabe/journal/objectchooser.py
@@ -0,0 +1,199 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+
+import gobject
+import gtk
+import wnck
+
+from sugar.graphics import style
+from sugar.graphics.toolbutton import ToolButton
+
+from jarabe.journal.listview import BaseListView
+from jarabe.journal.listmodel import ListModel
+from jarabe.journal.journaltoolbox import SearchToolbar
+from jarabe.journal.volumestoolbar import VolumesToolbar
+
+class ObjectChooser(gtk.Window):
+
+ __gtype_name__ = 'ObjectChooser'
+
+ __gsignals__ = {
+ 'response': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([int]))
+ }
+
+ def __init__(self, parent=None, what_filter=''):
+ gtk.Window.__init__(self)
+ self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.set_decorated(False)
+ self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.set_border_width(style.LINE_WIDTH)
+
+ self._selected_object_id = None
+
+ self.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
+ self.connect('visibility-notify-event',
+ self.__visibility_notify_event_cb)
+ self.connect('delete-event', self.__delete_event_cb)
+ self.connect('key-press-event', self.__key_press_event_cb)
+
+ if parent is None:
+ logging.warning('ObjectChooser: No parent window specified')
+ else:
+ self.connect('realize', self.__realize_cb, parent)
+
+ screen = wnck.screen_get_default()
+ screen.connect('window-closed', self.__window_closed_cb, parent)
+
+ vbox = gtk.VBox()
+ self.add(vbox)
+ vbox.show()
+
+ title_box = TitleBox()
+ title_box.connect('volume-changed', self.__volume_changed_cb)
+ title_box.close_button.connect('clicked',
+ self.__close_button_clicked_cb)
+ title_box.set_size_request(-1, style.GRID_CELL_SIZE)
+ vbox.pack_start(title_box, expand=False)
+ title_box.show()
+
+ separator = gtk.HSeparator()
+ vbox.pack_start(separator, expand=False)
+ separator.show()
+
+ self._toolbar = SearchToolbar()
+ self._toolbar.connect('query-changed', self.__query_changed_cb)
+ self._toolbar.set_size_request(-1, style.GRID_CELL_SIZE)
+ vbox.pack_start(self._toolbar, expand=False)
+ self._toolbar.show()
+
+ self._list_view = ChooserListView()
+ self._list_view.connect('entry-activated', self.__entry_activated_cb)
+ vbox.pack_start(self._list_view)
+ self._list_view.show()
+
+ self._toolbar.set_mount_point('/')
+
+ width = gtk.gdk.screen_width() - style.GRID_CELL_SIZE * 2
+ height = gtk.gdk.screen_height() - style.GRID_CELL_SIZE * 2
+ self.set_size_request(width, height)
+
+ if what_filter:
+ self._toolbar.set_what_filter(what_filter)
+
+ def __realize_cb(self, chooser, parent):
+ self.window.set_transient_for(parent)
+ # TODO: Should we disconnect the signal here?
+
+ def __window_closed_cb(self, screen, window, parent):
+ if window.get_xid() == parent.xid:
+ self.destroy()
+
+ def __entry_activated_cb(self, list_view, uid):
+ self._selected_object_id = uid
+ self.emit('response', gtk.RESPONSE_ACCEPT)
+
+ def __delete_event_cb(self, chooser, event):
+ self.emit('response', gtk.RESPONSE_DELETE_EVENT)
+
+ def __key_press_event_cb(self, widget, event):
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == 'Escape':
+ self.emit('response', gtk.RESPONSE_DELETE_EVENT)
+
+ def __close_button_clicked_cb(self, button):
+ self.emit('response', gtk.RESPONSE_DELETE_EVENT)
+
+ def get_selected_object_id(self):
+ return self._selected_object_id
+
+ def __query_changed_cb(self, toolbar, query):
+ self._list_view.update_with_query(query)
+
+ def __volume_changed_cb(self, volume_toolbar, mount_point):
+ logging.debug('Selected volume: %r.', mount_point)
+ self._toolbar.set_mount_point(mount_point)
+
+ def __visibility_notify_event_cb(self, window, event):
+ logging.debug('visibility_notify_event_cb %r', self)
+ visible = event.state == gtk.gdk.VISIBILITY_FULLY_OBSCURED
+ self._list_view.set_is_visible(visible)
+
+class TitleBox(VolumesToolbar):
+ __gtype_name__ = 'TitleBox'
+
+ def __init__(self):
+ VolumesToolbar.__init__(self)
+
+ label = gtk.Label()
+ label.set_markup('<b>%s</b>' % _('Choose an object'))
+ label.set_alignment(0, 0.5)
+ self._add_widget(label, expand=True)
+
+ self.close_button = ToolButton(icon_name='dialog-cancel')
+ self.close_button.set_tooltip(_('Close'))
+ self.insert(self.close_button, -1)
+ self.close_button.show()
+
+ def _add_widget(self, widget, expand=False):
+ tool_item = gtk.ToolItem()
+ tool_item.set_expand(expand)
+
+ tool_item.add(widget)
+ widget.show()
+
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+class ChooserListView(BaseListView):
+ __gtype_name__ = 'ChooserListView'
+
+ __gsignals__ = {
+ 'entry-activated': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ }
+
+ def __init__(self):
+ BaseListView.__init__(self)
+
+ self.cell_icon.props.show_palette = False
+ self.tree_view.props.hover_selection = True
+
+ self.tree_view.connect('button-release-event',
+ self.__button_release_event_cb)
+
+ def __entry_activated_cb(self, entry):
+ self.emit('entry-activated', entry)
+
+ def __button_release_event_cb(self, tree_view, event):
+ if event.window != tree_view.get_bin_window():
+ return False
+
+ pos = tree_view.get_path_at_pos(event.x, event.y)
+ if pos is None:
+ return False
+
+ path, column_, x_, y_ = pos
+ uid = tree_view.get_model()[path][ListModel.COLUMN_UID]
+ self.emit('entry-activated', uid)
+
+ return False
+
diff --git a/shell/src/jarabe/journal/palettes.py b/shell/src/jarabe/journal/palettes.py
new file mode 100644
index 0000000..7c3e5ff
--- /dev/null
+++ b/shell/src/jarabe/journal/palettes.py
@@ -0,0 +1,235 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+
+import gobject
+import gtk
+import gconf
+
+from sugar.graphics import style
+from sugar.graphics.palette import Palette
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.icon import Icon
+from sugar.graphics.xocolor import XoColor
+from sugar import mime
+
+from jarabe.model import bundleregistry
+from jarabe.model import friends
+from jarabe.model import filetransfer
+from jarabe.model import mimeregistry
+from jarabe.journal import misc
+from jarabe.journal import model
+
+class ObjectPalette(Palette):
+
+ __gtype_name__ = 'ObjectPalette'
+
+ __gsignals__ = {
+ 'detail-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ }
+
+ def __init__(self, metadata, detail=False):
+
+ self._metadata = metadata
+ self._temp_file_path = None
+
+ activity_icon = Icon(icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
+ activity_icon.props.file = misc.get_icon_name(metadata)
+ activity_icon.props.xo_color = misc.get_icon_color(metadata)
+
+ if metadata.has_key('title'):
+ title = gobject.markup_escape_text(metadata['title'])
+ else:
+ title = _('Untitled')
+
+ Palette.__init__(self, primary_text=title,
+ icon=activity_icon)
+
+ if metadata.get('activity_id', ''):
+ resume_label = _('Resume')
+ resume_with_label = _('Resume with')
+ else:
+ resume_label = _('Start')
+ resume_with_label = _('Start with')
+ menu_item = MenuItem(resume_label, 'activity-start')
+ menu_item.connect('activate', self.__start_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ menu_item = MenuItem(resume_with_label, 'activity-start')
+ self.menu.append(menu_item)
+ menu_item.show()
+ start_with_menu = StartWithMenu(self._metadata)
+ menu_item.set_submenu(start_with_menu)
+
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ menu_item = MenuItem(_('Copy'))
+ icon = Icon(icon_name='edit-copy', xo_color=color,
+ icon_size=gtk.ICON_SIZE_MENU)
+ menu_item.set_image(icon)
+ menu_item.connect('activate', self.__copy_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ menu_item = MenuItem(_('Send to'), 'document-send')
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ friends_menu = FriendsMenu()
+ friends_menu.connect('friend-selected', self.__friend_selected_cb)
+ menu_item.set_submenu(friends_menu)
+
+ if detail == True:
+ menu_item = MenuItem(_('View Details'), 'go-right')
+ menu_item.connect('activate', self.__detail_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ menu_item = MenuItem(_('Erase'), 'list-remove')
+ menu_item.connect('activate', self.__erase_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ def __start_activate_cb(self, menu_item):
+ misc.resume(self._metadata)
+
+ def __copy_activate_cb(self, menu_item):
+ clipboard = gtk.Clipboard()
+ clipboard.set_with_data([('text/uri-list', 0, 0)],
+ self.__clipboard_get_func_cb,
+ self.__clipboard_clear_func_cb)
+
+ def __clipboard_get_func_cb(self, clipboard, selection_data, info, data):
+ # Get hold of a reference so the temp file doesn't get deleted
+ self._temp_file_path = model.get_file(self._metadata['uid'])
+ logging.debug('__clipboard_get_func_cb %r', self._temp_file_path)
+ selection_data.set_uris(['file://' + self._temp_file_path])
+
+ def __clipboard_clear_func_cb(self, clipboard, data):
+ # Release and delete the temp file
+ self._temp_file_path = None
+
+ def __erase_activate_cb(self, menu_item):
+ model.delete(self._metadata['uid'])
+
+ def __detail_activate_cb(self, menu_item):
+ self.emit('detail-clicked', self._metadata['uid'])
+
+ def __friend_selected_cb(self, menu_item, buddy):
+ logging.debug('__friend_selected_cb')
+ file_name = model.get_file(self._metadata['uid'])
+
+ title = str(self._metadata['title'])
+ description = str(self._metadata.get('description', ''))
+ mime_type = str(self._metadata['mime_type'])
+
+ if not mime_type:
+ mime_type = mime.get_for_file(file_name)
+
+ filetransfer.start_transfer(buddy, file_name, title, description,
+ mime_type)
+
+class FriendsMenu(gtk.Menu):
+ __gtype_name__ = 'JournalFriendsMenu'
+
+ __gsignals__ = {
+ 'friend-selected' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([object])),
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ if filetransfer.file_transfer_available():
+ friends_model = friends.get_model()
+ for friend in friends_model:
+ if friend.is_present():
+ menu_item = MenuItem(text_label=friend.get_nick(),
+ icon_name='computer-xo',
+ xo_color=friend.get_color())
+ menu_item.connect('activate', self.__item_activate_cb,
+ friend)
+ self.append(menu_item)
+ menu_item.show()
+
+ if not self.get_children():
+ menu_item = MenuItem(_('No friends present'))
+ menu_item.set_sensitive(False)
+ self.append(menu_item)
+ menu_item.show()
+ else:
+ menu_item = MenuItem(_('No valid connection found'))
+ menu_item.set_sensitive(False)
+ self.append(menu_item)
+ menu_item.show()
+
+ def __item_activate_cb(self, menu_item, friend):
+ self.emit('friend-selected', friend)
+
+
+class StartWithMenu(gtk.Menu):
+ __gtype_name__ = 'JournalStartWithMenu'
+
+ def __init__(self, metadata):
+ gobject.GObject.__init__(self)
+
+ self._metadata = metadata
+
+ for activity_info in misc.get_activities(metadata):
+ menu_item = MenuItem(activity_info.get_name())
+ menu_item.set_image(Icon(file=activity_info.get_icon(),
+ icon_size=gtk.ICON_SIZE_MENU))
+ menu_item.connect('activate', self.__item_activate_cb,
+ activity_info.get_bundle_id())
+ self.append(menu_item)
+ menu_item.show()
+
+ if not self.get_children():
+ if metadata.get('activity_id', ''):
+ resume_label = _('No activity to resume entry')
+ else:
+ resume_label = _('No activity to start entry')
+ menu_item = MenuItem(resume_label)
+ menu_item.set_sensitive(False)
+ self.append(menu_item)
+ menu_item.show()
+
+ def __item_activate_cb(self, menu_item, service_name):
+ mime_type = self._metadata.get('mime_type', '')
+ if mime_type:
+ mime_registry = mimeregistry.get_registry()
+ mime_registry.set_default_activity(mime_type, service_name)
+ misc.resume(self._metadata, service_name)
+
+
+class BuddyPalette(Palette):
+ def __init__(self, buddy):
+ self._buddy = buddy
+
+ nick, colors = buddy
+ buddy_icon = Icon(icon_name='computer-xo',
+ icon_size=style.STANDARD_ICON_SIZE,
+ xo_color=XoColor(colors))
+
+ Palette.__init__(self, primary_text=nick,
+ icon=buddy_icon)
+
+ # TODO: Support actions on buddies, like make friend, invite, etc.
diff --git a/shell/src/jarabe/journal/volumestoolbar.py b/shell/src/jarabe/journal/volumestoolbar.py
new file mode 100644
index 0000000..8b7786f
--- /dev/null
+++ b/shell/src/jarabe/journal/volumestoolbar.py
@@ -0,0 +1,207 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import os
+from gettext import gettext as _
+
+import gobject
+import gio
+import gtk
+import gconf
+
+from sugar.graphics.radiotoolbutton import RadioToolButton
+from sugar.graphics.palette import Palette
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.journal import model
+from jarabe.view.palettes import VolumePalette
+
+class VolumesToolbar(gtk.Toolbar):
+ __gtype_name__ = 'VolumesToolbar'
+
+ __gsignals__ = {
+ 'volume-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ 'volume-error': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str, str]))
+ }
+
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+ self._mount_added_hid = None
+ self._mount_removed_hid = None
+
+ button = JournalButton()
+ button.set_palette(Palette(_('Journal')))
+ button.connect('toggled', self._button_toggled_cb)
+ self.insert(button, 0)
+ button.show()
+ self._volume_buttons = [button]
+
+ self.connect('destroy', self.__destroy_cb)
+
+ gobject.idle_add(self._set_up_volumes)
+
+ def __destroy_cb(self, widget):
+ volume_monitor = gio.volume_monitor_get()
+ volume_monitor.disconnect(self._mount_added_hid)
+ volume_monitor.disconnect(self._mount_removed_hid)
+
+ def _set_up_volumes(self):
+ volume_monitor = gio.volume_monitor_get()
+ self._mount_added_hid = \
+ volume_monitor.connect('mount-added', self.__mount_added_cb)
+ self._mount_removed_hid = \
+ volume_monitor.connect('mount-removed', self.__mount_removed_cb)
+
+ for mount in volume_monitor.get_mounts():
+ self._add_button(mount)
+
+ def __mount_added_cb(self, volume_monitor, mount):
+ self._add_button(mount)
+
+ def __mount_removed_cb(self, volume_monitor, mount):
+ self._remove_button(mount)
+
+ def _add_button(self, mount):
+ logging.debug('VolumeToolbar._add_button: %r', mount.get_name())
+
+ button = VolumeButton(mount)
+ button.props.group = self._volume_buttons[0]
+ button.connect('toggled', self._button_toggled_cb)
+ button.connect('volume-error', self.__volume_error_cb)
+ position = self.get_item_index(self._volume_buttons[-1]) + 1
+ self.insert(button, position)
+ button.show()
+
+ self._volume_buttons.append(button)
+
+ if len(self.get_children()) > 1:
+ self.show()
+
+ def __volume_error_cb(self, button, strerror, severity):
+ self.emit('volume-error', strerror, severity)
+
+ def _button_toggled_cb(self, button):
+ if button.props.active:
+ self.emit('volume-changed', button.mount_point)
+
+ def _unmount_activated_cb(self, menu_item, mount):
+ logging.debug('VolumesToolbar._unmount_activated_cb: %r', mount)
+ mount.unmount(self.__unmount_cb)
+
+ def __unmount_cb(self, source, result):
+ logging.debug('__unmount_cb %r %r', source, result)
+
+ def _get_button_for_mount(self, mount):
+ mount_point = mount.get_root().get_path()
+ for button in self.get_children():
+ if button.mount_point == mount_point:
+ return button
+ logging.error('Couldnt find button with mount_point %r', mount_point)
+ return None
+
+ def _remove_button(self, mount):
+ button = self._get_button_for_mount(mount)
+ self._volume_buttons.remove(button)
+ self.remove(button)
+ self.get_children()[0].props.active = True
+
+ if len(self.get_children()) < 2:
+ self.hide()
+
+ def set_active_volume(self, mount):
+ button = self._get_button_for_mount(mount)
+ button.props.active = True
+
+class BaseButton(RadioToolButton):
+ __gsignals__ = {
+ 'volume-error': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str, str]))
+ }
+
+ def __init__(self, mount_point):
+ RadioToolButton.__init__(self)
+
+ self.mount_point = mount_point
+
+ self.drag_dest_set(gtk.DEST_DEFAULT_ALL,
+ [('journal-object-id', 0, 0)],
+ gtk.gdk.ACTION_COPY)
+ self.connect('drag-data-received', self._drag_data_received_cb)
+
+ def _drag_data_received_cb(self, widget, drag_context, x, y, selection_data,
+ info, timestamp):
+ object_id = selection_data.data
+ metadata = model.get(object_id)
+ file_path = model.get_file(metadata['uid'])
+ if not file_path or not os.path.exists(file_path):
+ logging.warn('File does not exist')
+ self.emit('volume-error', _('Entries without a file cannot'
+ ' be copied'), _('Warning'))
+ return
+
+ try:
+ model.copy(metadata, self.mount_point)
+ except IOError:
+ logging.exception('BaseButton._drag_data_received_cb: Error'
+ 'while copying')
+ self.emit('volume-error', _('Input/Output error'), _('Error'))
+
+class VolumeButton(BaseButton):
+ def __init__(self, mount):
+ self._mount = mount
+ mount_point = mount.get_root().get_path()
+ BaseButton.__init__(self, mount_point)
+
+ icon_name = None
+ icon_theme = gtk.icon_theme_get_default()
+ for icon_name in mount.get_icon().props.names:
+ icon_info = icon_theme.lookup_icon(icon_name,
+ gtk.ICON_SIZE_LARGE_TOOLBAR, 0)
+ if icon_info is not None:
+ break
+
+ if icon_name is None:
+ icon_name = 'drive'
+
+ self.props.named_icon = icon_name
+
+ # TODO: retrieve the colors from the owner of the device
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ self.props.xo_color = color
+
+ def create_palette(self):
+ palette = VolumePalette(self._mount)
+ #palette.props.invoker = FrameWidgetInvoker(self)
+ #palette.set_group_id('frame')
+ return palette
+
+class JournalButton(BaseButton):
+ def __init__(self):
+ BaseButton.__init__(self, mount_point='/')
+
+ self.props.named_icon = 'activity-journal'
+
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ self.props.xo_color = color
+
diff --git a/shell/src/jarabe/model/Makefile.am b/shell/src/jarabe/model/Makefile.am
new file mode 100644
index 0000000..92e8712
--- /dev/null
+++ b/shell/src/jarabe/model/Makefile.am
@@ -0,0 +1,19 @@
+sugardir = $(pythondir)/jarabe/model
+sugar_PYTHON = \
+ adhoc.py \
+ __init__.py \
+ buddy.py \
+ bundleregistry.py \
+ filetransfer.py \
+ friends.py \
+ invites.py \
+ olpcmesh.py \
+ mimeregistry.py \
+ neighborhood.py \
+ network.py \
+ notifications.py \
+ shell.py \
+ screen.py \
+ session.py \
+ sound.py \
+ telepathyclient.py
diff --git a/shell/src/jarabe/model/__init__.py b/shell/src/jarabe/model/__init__.py
new file mode 100644
index 0000000..a9dd95a
--- /dev/null
+++ b/shell/src/jarabe/model/__init__.py
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
diff --git a/shell/src/jarabe/model/adhoc.py b/shell/src/jarabe/model/adhoc.py
new file mode 100644
index 0000000..ad0c941
--- /dev/null
+++ b/shell/src/jarabe/model/adhoc.py
@@ -0,0 +1,292 @@
+# Copyright (C) 2010 One Laptop per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import dbus
+import gobject
+
+from jarabe.model import network
+from jarabe.model.network import Settings
+from sugar.util import unique_id
+from jarabe.model.network import IP4Config
+
+_NM_SERVICE = 'org.freedesktop.NetworkManager'
+_NM_IFACE = 'org.freedesktop.NetworkManager'
+_NM_PATH = '/org/freedesktop/NetworkManager'
+_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
+_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
+_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
+_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
+
+
+_adhoc_manager_instance = None
+def get_adhoc_manager_instance():
+ global _adhoc_manager_instance
+ if _adhoc_manager_instance is None:
+ _adhoc_manager_instance = AdHocManager()
+ return _adhoc_manager_instance
+
+
+class AdHocManager(gobject.GObject):
+ """To mimic the mesh behavior on devices where mesh hardware is
+ not available we support the creation of an Ad-hoc network on
+ three channels 1, 6, 11. If Sugar sees no "known" network when it
+ starts, it does autoconnect to an Ad-hoc network.
+
+ """
+
+ __gsignals__ = {
+ 'members-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
+ 'state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
+ }
+
+ _AUTOCONNECT_TIMEOUT = 30
+ _CHANNEL_1 = 1
+ _CHANNEL_6 = 6
+ _CHANNEL_11 = 11
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._bus = dbus.SystemBus()
+ self._device = None
+ self._idle_source = 0
+ self._listening_called = 0
+ self._device_state = network.DEVICE_STATE_UNKNOWN
+
+ self._current_channel = None
+ self._networks = {self._CHANNEL_1: None,
+ self._CHANNEL_6: None,
+ self._CHANNEL_11: None}
+
+ def start_listening(self, device):
+ self._listening_called += 1
+ if self._listening_called > 1:
+ raise RuntimeError('The start listening method can' \
+ ' only be called once.')
+
+ self._device = device
+ props = dbus.Interface(device, 'org.freedesktop.DBus.Properties')
+ self._device_state = props.Get(_NM_DEVICE_IFACE, 'State')
+
+ self._bus.add_signal_receiver(self.__device_state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
+ def stop_listening(self):
+ self._bus.remove_signal_receiver(self.__device_state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+ self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
+ def __device_state_changed_cb(self, new_state, old_state, reason):
+ self._device_state = new_state
+ self._update_state()
+
+ def __wireless_properties_changed_cb(self, properties):
+ if 'ActiveAccessPoint' in properties and \
+ properties['ActiveAccessPoint'] != '/':
+ active_ap = self._bus.get_object(_NM_SERVICE,
+ properties['ActiveAccessPoint'])
+ props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
+ props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
+ reply_handler=self.__get_all_ap_props_reply_cb,
+ error_handler=self.__get_all_ap_props_error_cb)
+
+ def __get_all_ap_props_reply_cb(self, properties):
+ if properties['Mode'] == network.NM_802_11_MODE_ADHOC and \
+ 'Frequency' in properties:
+ frequency = properties['Frequency']
+ self._current_channel = network.frequency_to_channel(frequency)
+ else:
+ self._current_channel = None
+ self._update_state()
+
+ def __get_all_ap_props_error_cb(self, err):
+ logging.error('Error getting the access point properties: %s', err)
+
+ def _update_state(self):
+ self.emit('state-changed', self._current_channel, self._device_state)
+
+ def _have_configured_connections(self):
+ return len(network.get_settings().connections) > 0
+
+ def autoconnect(self):
+ """Autoconnect to an Ad-hoc network"""
+ if self._device_state != network.DEVICE_STATE_DISCONNECTED:
+ return
+ elif self._have_configured_connections():
+ self._autoconnect_adhoc_timer()
+ else:
+ self._autoconnect_adhoc()
+
+ def _autoconnect_adhoc_timer(self):
+ """Start a timer which basically looks for 30 seconds of inactivity
+ on the device, then does autoconnect to an Ad-hoc network.
+
+ """
+ if self._idle_source != 0:
+ gobject.source_remove(self._idle_source)
+ self._idle_source = gobject.timeout_add_seconds( \
+ self._AUTOCONNECT_TIMEOUT, self.__idle_check_cb)
+
+ def __idle_check_cb(self):
+ if self._device_state == network.DEVICE_STATE_DISCONNECTED:
+ logging.debug("Connect to Ad-hoc network due to inactivity.")
+ self._autoconnect_adhoc()
+ return False
+
+ def _autoconnect_adhoc(self):
+ """First we try if there is an Ad-hoc network that is used by other
+ learners in the area, if not we default to channel 1.
+
+ """
+ if self._networks[self._CHANNEL_1] is not None:
+ self._connect(self._CHANNEL_1)
+ elif self._networks[self._CHANNEL_6] is not None:
+ self._connect(self._CHANNEL_6)
+ elif self._networks[self._CHANNEL_11] is not None:
+ self._connect(self._CHANNEL_11)
+ else:
+ self._connect(self._CHANNEL_1)
+
+ def activate_channel(self, channel):
+ """Activate a sugar Ad-hoc network.
+
+ Keyword arguments:
+ channel -- Channel to connect to (should be 1, 6, 11)
+
+ """
+ self._connect(channel)
+
+ def _connect(self, channel):
+ name = "Ad-hoc Network %d" % channel
+ connection = network.find_connection_by_ssid(name)
+ if connection is None:
+ settings = Settings()
+ settings.connection.id = name
+ settings.connection.uuid = unique_id()
+ settings.connection.type = '802-11-wireless'
+ settings.wireless.ssid = dbus.ByteArray(name)
+ settings.wireless.band = 'bg'
+ settings.wireless.channel = channel
+ settings.wireless.mode = 'adhoc'
+ settings.ip4_config = IP4Config()
+ settings.ip4_config.method = 'link-local'
+
+ connection = network.add_connection(name, settings)
+
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+
+ netmgr.ActivateConnection(network.SETTINGS_SERVICE,
+ connection.path,
+ self._device.object_path,
+ '/',
+ reply_handler=self.__activate_reply_cb,
+ error_handler=self.__activate_error_cb)
+
+ def deactivate_active_channel(self):
+ """Deactivate the current active channel."""
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+
+ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
+ netmgr_props.Get(_NM_IFACE, 'ActiveConnections', \
+ reply_handler=self.__get_active_connections_reply_cb,
+ error_handler=self.__get_active_connections_error_cb)
+
+ def __get_active_connections_reply_cb(self, active_connections_o):
+ for connection_o in active_connections_o:
+ obj = self._bus.get_object(_NM_IFACE, connection_o)
+ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
+ if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
+ access_point_o = props.Get(_NM_ACTIVE_CONN_IFACE,
+ 'SpecificObject')
+ if access_point_o != '/':
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+ netmgr.DeactivateConnection(connection_o)
+
+ def __get_active_connections_error_cb(self, err):
+ logging.error('Error getting the active connections: %s', err)
+
+ def __activate_reply_cb(self, connection):
+ logging.debug('Ad-hoc network created: %s', connection)
+
+ def __activate_error_cb(self, err):
+ logging.error('Failed to create Ad-hoc network: %s', err)
+
+ def add_access_point(self, access_point):
+ """Add an access point to a network and notify the view to idicate
+ the member change.
+
+ Keyword arguments:
+ access_point -- Access Point
+
+ """
+ if access_point.name.endswith(' 1'):
+ self._networks[self._CHANNEL_1] = access_point
+ self.emit('members-changed', self._CHANNEL_1, True)
+ elif access_point.name.endswith(' 6'):
+ self._networks[self._CHANNEL_6] = access_point
+ self.emit('members-changed', self._CHANNEL_6, True)
+ elif access_point.name.endswith('11'):
+ self._networks[self._CHANNEL_11] = access_point
+ self.emit('members-changed', self._CHANNEL_11, True)
+
+ def is_sugar_adhoc_access_point(self, ap_object_path):
+ """Checks whether an access point is part of a sugar Ad-hoc network.
+
+ Keyword arguments:
+ ap_object_path -- Access Point object path
+
+ Return: Boolean
+
+ """
+ for access_point in self._networks.values():
+ if access_point is not None:
+ if access_point.model.object_path == ap_object_path:
+ return True
+ return False
+
+ def remove_access_point(self, ap_object_path):
+ """Remove an access point from a sugar Ad-hoc network.
+
+ Keyword arguments:
+ ap_object_path -- Access Point object path
+
+ """
+ for channel in self._networks:
+ if self._networks[channel] is not None:
+ if self._networks[channel].model.object_path == ap_object_path:
+ self.emit('members-changed', channel, False)
+ self._networks[channel] = None
+ break
diff --git a/shell/src/jarabe/model/buddy.py b/shell/src/jarabe/model/buddy.py
new file mode 100644
index 0000000..6cf7be9
--- /dev/null
+++ b/shell/src/jarabe/model/buddy.py
@@ -0,0 +1,250 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import gobject
+import gconf
+import dbus
+from telepathy.client import Connection
+from telepathy.interfaces import CONNECTION
+
+from sugar.graphics.xocolor import XoColor
+from sugar.profile import get_profile
+
+from jarabe.util.telepathy import connection_watcher
+
+_NOT_PRESENT_COLOR = "#d5d5d5,#FFFFFF"
+
+CONNECTION_INTERFACE_BUDDY_INFO = 'org.laptop.Telepathy.BuddyInfo'
+
+class BaseBuddyModel(gobject.GObject):
+ __gtype_name__ = 'SugarBaseBuddyModel'
+
+ def __init__(self, **kwargs):
+ self._key = None
+ self._nick = None
+ self._color = None
+ self._tags = None
+ self._present = False
+ self._current_activity = None
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ def is_present(self):
+ return self._present
+
+ def set_present(self, present):
+ self._present = present
+
+ present = gobject.property(type=bool, default=False, getter=is_present,
+ setter=set_present)
+
+ def get_nick(self):
+ return self._nick
+
+ def set_nick(self, nick):
+ self._nick = nick
+
+ nick = gobject.property(type=object, getter=get_nick, setter=set_nick)
+
+ def get_key(self):
+ return self._key
+
+ def set_key(self, key):
+ self._key = key
+
+ key = gobject.property(type=object, getter=get_key, setter=set_key)
+
+ def get_color(self):
+ return self._color
+
+ def set_color(self, color):
+ self._color = color
+
+ color = gobject.property(type=object, getter=get_color, setter=set_color)
+
+ def get_tags(self):
+ return self._tags
+
+ tags = gobject.property(type=object, getter=get_tags)
+
+ def get_current_activity(self):
+ return self._current_activity
+
+ def set_current_activity(self, current_activity):
+ if self._current_activity != current_activity:
+ self._current_activity = current_activity
+ self.notify('current-activity')
+
+ current_activity = gobject.property(type=object,
+ getter=get_current_activity,
+ setter=set_current_activity)
+
+ def is_owner(self):
+ raise NotImplementedError
+
+ def get_buddy(self):
+ raise NotImplementedError
+
+
+class OwnerBuddyModel(BaseBuddyModel):
+ __gtype_name__ = 'SugarOwnerBuddyModel'
+ def __init__(self):
+ BaseBuddyModel.__init__(self)
+ self.props.present = True
+
+ client = gconf.client_get_default()
+ self.props.nick = client.get_string('/desktop/sugar/user/nick')
+ color = client.get_string('/desktop/sugar/user/color')
+ self.props.color = XoColor(color)
+
+ self.props.key = get_profile().pubkey
+
+ self.connect('notify::nick', self.__property_changed_cb)
+ self.connect('notify::color', self.__property_changed_cb)
+ self.connect('notify::current-activity',
+ self.__current_activity_changed_cb)
+
+ bus = dbus.SessionBus()
+ bus.add_signal_receiver(
+ self.__name_owner_changed_cb,
+ signal_name='NameOwnerChanged',
+ dbus_interface='org.freedesktop.DBus')
+
+ bus_object = bus.get_object(dbus.BUS_DAEMON_NAME, dbus.BUS_DAEMON_PATH)
+ for service in bus_object.ListNames(
+ dbus_interface=dbus.BUS_DAEMON_IFACE):
+ if service.startswith('org.freedesktop.Telepathy.Connection.'):
+ path = '/%s' % service.replace('.', '/')
+ Connection(service, path, bus,
+ ready_handler=self.__connection_ready_cb)
+
+ def __connection_ready_cb(self, connection):
+ self._sync_properties_on_connection(connection)
+
+ def __name_owner_changed_cb(self, name, old, new):
+ if name.startswith(CONNECTION) and not old and new:
+ path = '/' + name.replace('.', '/')
+ Connection(name, path, ready_handler=self.__connection_ready_cb)
+
+ def __property_changed_cb(self, pspec):
+ self._sync_properties()
+
+ def __current_activity_changed_cb(self, pspec):
+ conn_watcher = connection_watcher.get_instance()
+ for connection in conn_watcher.get_connections():
+ if self.props.current_activity is not None:
+ activity_id = self.props.current_activity.activity_id
+ room_handle = self.props.current_activity.room_handle
+ else:
+ activity_id = ''
+ room_handle = 0
+
+ connection[CONNECTION_INTERFACE_BUDDY_INFO].SetCurrentActivity(
+ activity_id,
+ room_handle,
+ reply_handler=self.__set_current_activity_cb,
+ error_handler=self.__error_handler_cb)
+
+ def __set_current_activity_cb(self):
+ logging.debug('__set_current_activity_cb')
+
+ def _sync_properties(self):
+ conn_watcher = connection_watcher.get_instance()
+ for connection in conn_watcher.get_connections():
+ self._sync_properties_on_connection(connection)
+
+ def _sync_properties_on_connection(self, connection):
+ if CONNECTION_INTERFACE_BUDDY_INFO in connection:
+ properties = {}
+ if self.props.key is not None:
+ properties['key'] = dbus.ByteArray(self.props.key)
+ if self.props.color is not None:
+ properties['color'] = self.props.color.to_string()
+
+ logging.debug('calling SetProperties with %r', properties)
+ connection[CONNECTION_INTERFACE_BUDDY_INFO].SetProperties(
+ properties,
+ reply_handler=self.__set_properties_cb,
+ error_handler=self.__error_handler_cb)
+
+ def __set_properties_cb(self):
+ logging.debug('__set_properties_cb')
+
+ def __error_handler_cb(self, error):
+ raise RuntimeError(error)
+
+ def __connection_added_cb(self, conn_watcher, connection):
+ self._sync_properties_on_connection(connection)
+
+ def is_owner(self):
+ return True
+
+ def get_buddy(self):
+ raise NotImplementedError
+
+
+_owner_instance = None
+def get_owner_instance():
+ global _owner_instance
+ if _owner_instance is None:
+ _owner_instance = OwnerBuddyModel()
+ return _owner_instance
+
+
+class BuddyModel(BaseBuddyModel):
+ __gtype_name__ = 'SugarBuddyModel'
+ def __init__(self, **kwargs):
+
+ self._account = None
+ self._contact_id = None
+
+ BaseBuddyModel.__init__(self, **kwargs)
+
+ def is_owner(self):
+ return False
+
+ def get_buddy(self):
+ raise NotImplementedError
+
+ def get_account(self):
+ return self._account
+
+ def set_account(self, account):
+ self._account = account
+
+ account = gobject.property(type=object, getter=get_account,
+ setter=set_account)
+
+ def get_contact_id(self):
+ return self._contact_id
+
+ def set_contact_id(self, contact_id):
+ self._contact_id = contact_id
+
+ contact_id = gobject.property(type=object, getter=get_contact_id,
+ setter=set_contact_id)
+
+
+class FriendBuddyModel(BuddyModel):
+ __gtype_name__ = 'SugarFriendBuddyModel'
+ def __init__(self, nick, key):
+ BuddyModel.__init__(self, nick=nick, key=key)
+
+ def get_buddy(self):
+ raise NotImplementedError
diff --git a/shell/src/jarabe/model/bundleregistry.py b/shell/src/jarabe/model/bundleregistry.py
new file mode 100644
index 0000000..858655f
--- /dev/null
+++ b/shell/src/jarabe/model/bundleregistry.py
@@ -0,0 +1,444 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2009 Aleksey Lim
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+import traceback
+
+import gobject
+import gio
+import simplejson
+
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.bundle.contentbundle import ContentBundle
+from jarabe.journal.journalentrybundle import JournalEntryBundle
+from sugar.bundle.bundle import MalformedBundleException, \
+ AlreadyInstalledException, RegistrationException
+from sugar import env
+
+from jarabe import config
+from jarabe.model import mimeregistry
+
+class BundleRegistry(gobject.GObject):
+ """Tracks the available activity bundles"""
+
+ __gsignals__ = {
+ 'bundle-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'bundle-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'bundle-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self):
+ logging.debug('STARTUP: Loading the bundle registry')
+ gobject.GObject.__init__(self)
+
+ self._mime_defaults = self._load_mime_defaults()
+
+ self._bundles = []
+ # hold a reference to the monitors so they don't get disposed
+ self._gio_monitors = []
+
+ user_path = env.get_user_activities_path()
+ for activity_dir in [user_path, config.activities_path]:
+ self._scan_directory(activity_dir)
+ directory = gio.File(activity_dir)
+ monitor = directory.monitor_directory()
+ monitor.connect('changed', self.__file_monitor_changed_cb)
+ self._gio_monitors.append(monitor)
+
+ self._last_defaults_mtime = -1
+ self._favorite_bundles = {}
+
+ try:
+ self._load_favorites()
+ except Exception:
+ logging.exception('Error while loading favorite_activities.')
+
+ self._merge_default_favorites()
+
+ def __file_monitor_changed_cb(self, monitor, one_file, other_file,
+ event_type):
+ if not one_file.get_path().endswith('.activity'):
+ return
+ if event_type == gio.FILE_MONITOR_EVENT_CREATED:
+ self.add_bundle(one_file.get_path(), install_mime_type=True)
+ elif event_type == gio.FILE_MONITOR_EVENT_DELETED:
+ self.remove_bundle(one_file.get_path())
+
+ def _load_mime_defaults(self):
+ defaults = {}
+
+ f = open(os.path.join(config.data_path, 'mime.defaults'), 'r')
+ for line in f.readlines():
+ line = line.strip()
+ if line and not line.startswith('#'):
+ mime = line[:line.find(' ')]
+ handler = line[line.rfind(' ') + 1:]
+ defaults[mime] = handler
+ f.close()
+
+ return defaults
+
+ def _get_favorite_key(self, bundle_id, version):
+ """We use a string as a composite key for the favorites dictionary
+ because JSON doesn't support tuples and python won't accept a list
+ as a dictionary key.
+ """
+ if ' ' in bundle_id:
+ raise ValueError('bundle_id cannot contain spaces')
+ return '%s %s' % (bundle_id, version)
+
+ def _load_favorites(self):
+ favorites_path = env.get_profile_path('favorite_activities')
+ if os.path.exists(favorites_path):
+ favorites_data = simplejson.load(open(favorites_path))
+
+ favorite_bundles = favorites_data['favorites']
+ if not isinstance(favorite_bundles, dict):
+ raise ValueError('Invalid format in %s.' % favorites_path)
+ if favorite_bundles:
+ first_key = favorite_bundles.keys()[0]
+ if not isinstance(first_key, basestring):
+ raise ValueError('Invalid format in %s.' % favorites_path)
+
+ first_value = favorite_bundles.values()[0]
+ if first_value is not None and \
+ not isinstance(first_value, dict):
+ raise ValueError('Invalid format in %s.' % favorites_path)
+
+ self._last_defaults_mtime = float(favorites_data['defaults-mtime'])
+ self._favorite_bundles = favorite_bundles
+
+ def _merge_default_favorites(self):
+ default_activities = []
+ defaults_path = os.path.join(config.data_path, 'activities.defaults')
+ if os.path.exists(defaults_path):
+ file_mtime = os.stat(defaults_path).st_mtime
+ if file_mtime > self._last_defaults_mtime:
+ f = open(defaults_path, 'r')
+ for line in f.readlines():
+ line = line.strip()
+ if line and not line.startswith('#'):
+ default_activities.append(line)
+ f.close()
+ self._last_defaults_mtime = file_mtime
+
+ if not default_activities:
+ return
+
+ for bundle_id in default_activities:
+ max_version = -1
+ for bundle in self._bundles:
+ if bundle.get_bundle_id() == bundle_id and \
+ max_version < bundle.get_activity_version():
+ max_version = bundle.get_activity_version()
+
+ key = self._get_favorite_key(bundle_id, max_version)
+ if max_version > -1 and key not in self._favorite_bundles:
+ self._favorite_bundles[key] = None
+
+ logging.debug('After merging: %r', self._favorite_bundles)
+
+ self._write_favorites_file()
+
+ def get_bundle(self, bundle_id):
+ """Returns a bundle given service name or substring,
+ returns None if there is either no match, or more than one
+ match by substring."""
+ result = []
+ key = bundle_id.lower()
+
+ for bundle in self._bundles:
+ name = bundle.get_bundle_id()
+ if name == bundle_id:
+ return bundle
+ if key in name.lower():
+ result.append(bundle)
+ if len(result) == 1:
+ return result[0]
+ return None
+
+ def __iter__(self):
+ return self._bundles.__iter__()
+
+ def __len__(self):
+ return len(self._bundles)
+
+ def _scan_directory(self, path):
+ if not os.path.isdir(path):
+ return
+
+ # Sort by mtime to ensure a stable activity order
+ bundles = {}
+ for f in os.listdir(path):
+ if not f.endswith('.activity'):
+ continue
+ try:
+ bundle_dir = os.path.join(path, f)
+ if os.path.isdir(bundle_dir):
+ bundles[bundle_dir] = os.stat(bundle_dir).st_mtime
+ except Exception:
+ logging.error('Error while processing installed activity ' \
+ 'bundle %s:\n%s' % \
+ (bundle_dir, traceback.format_exc()))
+
+ bundle_dirs = bundles.keys()
+ bundle_dirs.sort(lambda d1, d2: cmp(bundles[d1], bundles[d2]))
+ for folder in bundle_dirs:
+ try:
+ self._add_bundle(folder)
+ except Exception, e:
+ logging.error('Error while processing installed activity ' \
+ 'bundle %s:\n%s' % \
+ (folder, traceback.format_exc()))
+
+ def add_bundle(self, bundle_path, install_mime_type=False):
+ bundle = self._add_bundle(bundle_path, install_mime_type)
+ if bundle is not None:
+ self._set_bundle_favorite(bundle.get_bundle_id(),
+ bundle.get_activity_version(),
+ True)
+ self.emit('bundle-added', bundle)
+ return True
+ else:
+ return False
+
+ def _add_bundle(self, bundle_path, install_mime_type=False):
+ logging.debug('STARTUP: Adding bundle %r', bundle_path)
+ try:
+ bundle = ActivityBundle(bundle_path)
+ if install_mime_type:
+ bundle.install_mime_type(bundle_path)
+ except MalformedBundleException:
+ logging.exception('Error loading bundle %r', bundle_path)
+ return None
+
+ bundle_id = bundle.get_bundle_id()
+ installed = self.get_bundle(bundle_id)
+
+ if installed is not None:
+ if installed.get_activity_version() >= \
+ bundle.get_activity_version():
+ logging.debug('Skip old version for %s', bundle_id)
+ return None
+ else:
+ logging.debug('Upgrade %s', bundle_id)
+ self.remove_bundle(installed.get_path())
+
+ self._bundles.append(bundle)
+ return bundle
+
+ def remove_bundle(self, bundle_path):
+ for bundle in self._bundles:
+ if bundle.get_path() == bundle_path:
+ self._bundles.remove(bundle)
+ self.emit('bundle-removed', bundle)
+ return True
+ return False
+
+ def get_activities_for_type(self, mime_type):
+ result = []
+
+ mime = mimeregistry.get_registry()
+ default_bundle_id = mime.get_default_activity(mime_type)
+ default_bundle = None
+
+ for bundle in self._bundles:
+ if bundle.get_mime_types() and mime_type in bundle.get_mime_types():
+
+ if bundle.get_bundle_id() == default_bundle_id:
+ default_bundle = bundle
+ elif self.get_default_for_type(mime_type) == \
+ bundle.get_bundle_id():
+ result.insert(0, bundle)
+ else:
+ result.append(bundle)
+
+ if default_bundle is not None:
+ result.insert(0, default_bundle)
+
+ return result
+
+ def get_default_for_type(self, mime_type):
+ if self._mime_defaults.has_key(mime_type):
+ return self._mime_defaults[mime_type]
+ else:
+ return None
+
+ def _find_bundle(self, bundle_id, version):
+ for bundle in self._bundles:
+ if bundle.get_bundle_id() == bundle_id and \
+ bundle.get_activity_version() == version:
+ return bundle
+ raise ValueError('No bundle %r with version %r exists.' % \
+ (bundle_id, version))
+
+ def set_bundle_favorite(self, bundle_id, version, favorite):
+ changed = self._set_bundle_favorite(bundle_id, version, favorite)
+ if changed:
+ bundle = self._find_bundle(bundle_id, version)
+ self.emit('bundle-changed', bundle)
+
+ def _set_bundle_favorite(self, bundle_id, version, favorite):
+ key = self._get_favorite_key(bundle_id, version)
+ if favorite and not key in self._favorite_bundles:
+ self._favorite_bundles[key] = None
+ elif not favorite and key in self._favorite_bundles:
+ del self._favorite_bundles[key]
+ else:
+ return False
+
+ self._write_favorites_file()
+ return True
+
+ def is_bundle_favorite(self, bundle_id, version):
+ key = self._get_favorite_key(bundle_id, version)
+ return key in self._favorite_bundles
+
+ def set_bundle_position(self, bundle_id, version, x, y):
+ key = self._get_favorite_key(bundle_id, version)
+ if key not in self._favorite_bundles:
+ raise ValueError('Bundle %s %s not favorite' % (bundle_id, version))
+
+ if self._favorite_bundles[key] is None:
+ self._favorite_bundles[key] = {}
+ if 'position' not in self._favorite_bundles[key] or \
+ [x, y] != self._favorite_bundles[key]['position']:
+ self._favorite_bundles[key]['position'] = [x, y]
+ else:
+ return
+
+ self._write_favorites_file()
+ bundle = self._find_bundle(bundle_id, version)
+ self.emit('bundle-changed', bundle)
+
+ def get_bundle_position(self, bundle_id, version):
+ """Get the coordinates where the user wants the representation of this
+ bundle to be displayed. Coordinates are relative to a 1000x1000 area.
+ """
+ key = self._get_favorite_key(bundle_id, version)
+ if key not in self._favorite_bundles or \
+ self._favorite_bundles[key] is None or \
+ 'position' not in self._favorite_bundles[key]:
+ return (-1, -1)
+ else:
+ return tuple(self._favorite_bundles[key]['position'])
+
+ def _write_favorites_file(self):
+ path = env.get_profile_path('favorite_activities')
+ favorites_data = {'defaults-mtime': self._last_defaults_mtime,
+ 'favorites': self._favorite_bundles}
+ simplejson.dump(favorites_data, open(path, 'w'), indent=1)
+
+ def is_installed(self, bundle):
+ # TODO treat ContentBundle in special way
+ # needs rethinking while fixing ContentBundle support
+ if isinstance(bundle, ContentBundle) or \
+ isinstance(bundle, JournalEntryBundle):
+ return bundle.is_installed()
+
+ for installed_bundle in self._bundles:
+ if bundle.get_bundle_id() == installed_bundle.get_bundle_id() and \
+ bundle.get_activity_version() == \
+ installed_bundle.get_activity_version():
+ return True
+ return False
+
+ def install(self, bundle, uid=None):
+ activities_path = env.get_user_activities_path()
+
+ for installed_bundle in self._bundles:
+ if bundle.get_bundle_id() == installed_bundle.get_bundle_id() and \
+ bundle.get_activity_version() <= \
+ installed_bundle.get_activity_version():
+ raise AlreadyInstalledException
+ elif bundle.get_bundle_id() == installed_bundle.get_bundle_id():
+ self.uninstall(installed_bundle, force=True)
+
+ install_dir = env.get_user_activities_path()
+ if isinstance(bundle, JournalEntryBundle):
+ install_path = bundle.install(uid)
+ else:
+ install_path = bundle.install(install_dir)
+
+ # TODO treat ContentBundle in special way
+ # needs rethinking while fixing ContentBundle support
+ if isinstance(bundle, ContentBundle) or \
+ isinstance(bundle, JournalEntryBundle):
+ pass
+ elif not self.add_bundle(install_path):
+ raise RegistrationException
+
+ def uninstall(self, bundle, force=False):
+ # TODO treat ContentBundle in special way
+ # needs rethinking while fixing ContentBundle support
+ if isinstance(bundle, ContentBundle) or \
+ isinstance(bundle, JournalEntryBundle):
+ if bundle.is_installed():
+ bundle.uninstall()
+ else:
+ logging.warning('Not uninstalling, bundle is not installed')
+ return
+
+ act = self.get_bundle(bundle.get_bundle_id())
+ if not force and \
+ act.get_activity_version() != bundle.get_activity_version():
+ logging.warning('Not uninstalling, different bundle present')
+ return
+
+ if not act.is_user_activity():
+ logging.debug('Do not uninstall system activity')
+ return
+
+ install_path = act.get_path()
+
+ bundle.uninstall(install_path, force)
+
+ if not self.remove_bundle(install_path):
+ raise RegistrationException
+
+ def upgrade(self, bundle):
+ act = self.get_bundle(bundle.get_bundle_id())
+ if act is None:
+ logging.warning('Activity not installed')
+ elif act.get_activity_version() == bundle.get_activity_version():
+ logging.debug('No upgrade needed, same version already installed.')
+ return
+ elif act.is_user_activity():
+ try:
+ self.uninstall(bundle, force=True)
+ except Exception:
+ logging.error('Uninstall failed, still trying to install ' \
+ 'newer bundle:\n' + \
+ traceback.format_exc())
+ else:
+ logging.warning('Unable to uninstall system activity, ' \
+ 'installing upgraded version in user activities')
+
+ self.install(bundle)
+
+_instance = None
+
+def get_registry():
+ global _instance
+ if not _instance:
+ _instance = BundleRegistry()
+ return _instance
+
diff --git a/shell/src/jarabe/model/filetransfer.py b/shell/src/jarabe/model/filetransfer.py
new file mode 100644
index 0000000..e0809bb
--- /dev/null
+++ b/shell/src/jarabe/model/filetransfer.py
@@ -0,0 +1,374 @@
+# Copyright (C) 2008 Tomeu Vizoso
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+import socket
+
+import gobject
+import gio
+import dbus
+from telepathy.interfaces import CONNECTION_INTERFACE_REQUESTS, CHANNEL
+from telepathy.constants import CONNECTION_HANDLE_TYPE_CONTACT, \
+ SOCKET_ADDRESS_TYPE_UNIX, \
+ SOCKET_ACCESS_CONTROL_LOCALHOST
+from telepathy.client import Connection, Channel
+
+from sugar.presence import presenceservice
+from sugar import dispatch
+
+from jarabe.util.telepathy import connection_watcher
+
+FT_STATE_NONE = 0
+FT_STATE_PENDING = 1
+FT_STATE_ACCEPTED = 2
+FT_STATE_OPEN = 3
+FT_STATE_COMPLETED = 4
+FT_STATE_CANCELLED = 5
+
+FT_REASON_NONE = 0
+FT_REASON_REQUESTED = 1
+FT_REASON_LOCAL_STOPPED = 2
+FT_REASON_REMOTE_STOPPED = 3
+FT_REASON_LOCAL_ERROR = 4
+FT_REASON_LOCAL_ERROR = 5
+FT_REASON_REMOTE_ERROR = 6
+
+# FIXME: use constants from tp-python once the spec is undrafted
+CHANNEL_TYPE_FILE_TRANSFER = \
+ 'org.freedesktop.Telepathy.Channel.Type.FileTransfer'
+
+# TODO Move to use splice_async() in Sugar 0.88
+class StreamSplicer(gobject.GObject):
+ _CHUNK_SIZE = 10240 # 10K
+ __gsignals__ = {
+ 'finished': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ }
+ def __init__(self, input_stream, output_stream):
+ gobject.GObject.__init__(self)
+
+ self._input_stream = input_stream
+ self._output_stream = output_stream
+ self._pending_buffers = []
+
+ def start(self):
+ self._input_stream.read_async(self._CHUNK_SIZE, self.__read_async_cb,
+ gobject.PRIORITY_LOW)
+
+ def __read_async_cb(self, input_stream, result):
+ data = input_stream.read_finish(result)
+
+ if not data:
+ logging.debug('closing input stream')
+ self._input_stream.close()
+ else:
+ self._pending_buffers.append(data)
+ self._input_stream.read_async(self._CHUNK_SIZE,
+ self.__read_async_cb,
+ gobject.PRIORITY_LOW)
+ self._write_next_buffer()
+
+ def __write_async_cb(self, output_stream, result, user_data):
+ count_ = output_stream.write_finish(result)
+
+ if not self._pending_buffers and \
+ not self._output_stream.has_pending() and \
+ not self._input_stream.has_pending():
+ logging.debug('closing output stream')
+ output_stream.close()
+ self.emit('finished')
+ else:
+ self._write_next_buffer()
+
+ def _write_next_buffer(self):
+ if self._pending_buffers and not self._output_stream.has_pending():
+ data = self._pending_buffers.pop(0)
+ # TODO: we pass the buffer as user_data because of
+ # http://bugzilla.gnome.org/show_bug.cgi?id=564102
+ self._output_stream.write_async(data, self.__write_async_cb,
+ gobject.PRIORITY_LOW,
+ user_data=data)
+
+class BaseFileTransfer(gobject.GObject):
+
+ def __init__(self, connection):
+ gobject.GObject.__init__(self)
+ self._connection = connection
+ self._state = FT_STATE_NONE
+ self._transferred_bytes = 0
+
+ self.channel = None
+ self.buddy = None
+ self.title = None
+ self.file_size = None
+ self.description = None
+ self.mime_type = None
+ self.initial_offset = 0
+ self.reason_last_change = FT_REASON_NONE
+
+ def set_channel(self, channel):
+ self.channel = channel
+ self.channel[CHANNEL_TYPE_FILE_TRANSFER].connect_to_signal(
+ 'FileTransferStateChanged', self.__state_changed_cb)
+ self.channel[CHANNEL_TYPE_FILE_TRANSFER].connect_to_signal(
+ 'TransferredBytesChanged', self.__transferred_bytes_changed_cb)
+ self.channel[CHANNEL_TYPE_FILE_TRANSFER].connect_to_signal(
+ 'InitialOffsetDefined', self.__initial_offset_defined_cb)
+
+ channel_properties = self.channel[dbus.PROPERTIES_IFACE]
+
+ props = channel_properties.GetAll(CHANNEL_TYPE_FILE_TRANSFER)
+ self._state = props['State']
+ self.title = props['Filename']
+ self.file_size = props['Size']
+ self.description = props['Description']
+ self.mime_type = props['ContentType']
+
+ handle = channel_properties.Get(CHANNEL, 'TargetHandle')
+ presence_service = presenceservice.get_instance()
+ self.buddy = presence_service.get_buddy_by_telepathy_handle(
+ self._connection.service_name,
+ self._connection.object_path,
+ handle)
+
+ def __transferred_bytes_changed_cb(self, transferred_bytes):
+ logging.debug('__transferred_bytes_changed_cb %r', transferred_bytes)
+ self.props.transferred_bytes = transferred_bytes
+
+ def _set_transferred_bytes(self, transferred_bytes):
+ self._transferred_bytes = transferred_bytes
+
+ def _get_transferred_bytes(self):
+ return self._transferred_bytes
+
+ transferred_bytes = gobject.property(type=int, default=0,
+ getter=_get_transferred_bytes, setter=_set_transferred_bytes)
+
+ def __initial_offset_defined_cb(self, offset):
+ logging.debug('__initial_offset_defined_cb %r', offset)
+ self.initial_offset = offset
+
+ def __state_changed_cb(self, state, reason):
+ logging.debug('__state_changed_cb %r %r', state, reason)
+ self.reason_last_change = reason
+ self.props.state = state
+
+ def _set_state(self, state):
+ self._state = state
+
+ def _get_state(self):
+ return self._state
+
+ state = gobject.property(type=int, getter=_get_state, setter=_set_state)
+
+ def cancel(self):
+ self.channel[CHANNEL].Close()
+
+class IncomingFileTransfer(BaseFileTransfer):
+ def __init__(self, connection, object_path, props):
+ BaseFileTransfer.__init__(self, connection)
+
+ channel = Channel(connection.service_name, object_path)
+ self.set_channel(channel)
+
+ self.connect('notify::state', self.__notify_state_cb)
+
+ self.destination_path = None
+ self._socket_address = None
+ self._socket = None
+ self._splicer = None
+
+ def accept(self, destination_path):
+ if os.path.exists(destination_path):
+ raise ValueError('Destination path already exists: %r' % \
+ destination_path)
+
+ self.destination_path = destination_path
+
+ channel_ft = self.channel[CHANNEL_TYPE_FILE_TRANSFER]
+ self._socket_address = channel_ft.AcceptFile(SOCKET_ADDRESS_TYPE_UNIX,
+ SOCKET_ACCESS_CONTROL_LOCALHOST, '', 0, byte_arrays=True)
+
+ def __notify_state_cb(self, file_transfer, pspec):
+ logging.debug('__notify_state_cb %r', self.props.state)
+ if self.props.state == FT_STATE_OPEN:
+ # Need to hold a reference to the socket so that python doesn't
+ # close the fd when it goes out of scope
+ self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ self._socket.connect(self._socket_address)
+ input_stream = gio.unix.InputStream(self._socket.fileno(), True)
+
+ destination_file = gio.File(self.destination_path)
+ if self.initial_offset == 0:
+ output_stream = destination_file.create()
+ else:
+ output_stream = destination_file.append_to()
+
+ # TODO: Use splice_async when it gets implemented
+ self._splicer = StreamSplicer(input_stream, output_stream)
+ self._splicer.start()
+
+class OutgoingFileTransfer(BaseFileTransfer):
+ def __init__(self, buddy, file_name, title, description, mime_type):
+
+ presence_service = presenceservice.get_instance()
+ name, path = presence_service.get_preferred_connection()
+ connection = Connection(name, path,
+ ready_handler=self.__connection_ready_cb)
+
+ BaseFileTransfer.__init__(self, connection)
+ self.connect('notify::state', self.__notify_state_cb)
+
+ self._file_name = file_name
+ self._socket_address = None
+ self._socket = None
+ self._splicer = None
+ self._output_stream = None
+
+ self.buddy = buddy.get_buddy()
+ self.title = title
+ self.file_size = os.stat(file_name).st_size
+ self.description = description
+ self.mime_type = mime_type
+
+ def __connection_ready_cb(self, connection):
+ handle = self._get_buddy_handle()
+
+ requests = connection[CONNECTION_INTERFACE_REQUESTS]
+ object_path, properties_ = requests.CreateChannel({
+ CHANNEL + '.ChannelType': CHANNEL_TYPE_FILE_TRANSFER,
+ CHANNEL + '.TargetHandleType': CONNECTION_HANDLE_TYPE_CONTACT,
+ CHANNEL + '.TargetHandle': handle,
+ CHANNEL_TYPE_FILE_TRANSFER + '.ContentType': self.mime_type,
+ CHANNEL_TYPE_FILE_TRANSFER + '.Filename': self.title,
+ CHANNEL_TYPE_FILE_TRANSFER + '.Size': self.file_size,
+ CHANNEL_TYPE_FILE_TRANSFER + '.Description': self.description,
+ CHANNEL_TYPE_FILE_TRANSFER + '.InitialOffset': 0})
+
+ self.set_channel(Channel(connection.service_name, object_path))
+
+ channel_file_transfer = self.channel[CHANNEL_TYPE_FILE_TRANSFER]
+ self._socket_address = channel_file_transfer.ProvideFile(
+ SOCKET_ADDRESS_TYPE_UNIX, SOCKET_ACCESS_CONTROL_LOCALHOST, '',
+ byte_arrays=True)
+
+ def _get_buddy_handle(self):
+ object_path = self.buddy.object_path()
+
+ bus = dbus.SessionBus()
+ remote_object = bus.get_object('org.laptop.Sugar.Presence', object_path)
+ ps_buddy = dbus.Interface(remote_object,
+ 'org.laptop.Sugar.Presence.Buddy')
+
+ handles = ps_buddy.GetTelepathyHandles()
+ logging.debug('_get_buddy_handle %r', handles)
+
+ bus_name, object_path, handle = handles[0]
+
+ return handle
+
+ def __notify_state_cb(self, file_transfer, pspec):
+ logging.debug('__notify_state_cb %r', self.props.state)
+ if self.props.state == FT_STATE_OPEN:
+ # Need to hold a reference to the socket so that python doesn't
+ # closes the fd when it goes out of scope
+ self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ self._socket.connect(self._socket_address)
+ output_stream = gio.unix.OutputStream(self._socket.fileno(), True)
+
+ logging.debug('opening %s for reading', self._file_name)
+ input_stream = gio.File(self._file_name).read()
+ if self.initial_offset > 0:
+ input_stream.skip(self.initial_offset)
+
+ # TODO: Use splice_async when it gets implemented
+ self._splicer = StreamSplicer(input_stream, output_stream)
+ self._splicer.start()
+
+ def cancel(self):
+ self.channel[CHANNEL].Close()
+
+def _new_channels_cb(connection, channels):
+ for object_path, props in channels:
+ if props[CHANNEL + '.ChannelType'] == CHANNEL_TYPE_FILE_TRANSFER and \
+ not props[CHANNEL + '.Requested']:
+
+ logging.debug('__new_channels_cb %r', object_path)
+
+ incoming_file_transfer = IncomingFileTransfer(connection,
+ object_path, props)
+ new_file_transfer.send(None, file_transfer=incoming_file_transfer)
+
+def _monitor_connection(connection):
+ logging.debug('connection added %r', connection)
+ connection[CONNECTION_INTERFACE_REQUESTS].connect_to_signal('NewChannels',
+ lambda channels: _new_channels_cb(connection, channels))
+
+def _connection_added_cb(conn_watcher, connection):
+ _monitor_connection(connection)
+
+def _connection_removed_cb(conn_watcher, connection):
+ logging.debug('connection removed %r', connection)
+
+def init():
+ conn_watcher = connection_watcher.get_instance()
+ conn_watcher.connect('connection-added', _connection_added_cb)
+ conn_watcher.connect('connection-removed', _connection_removed_cb)
+
+ for connection in conn_watcher.get_connections():
+ _monitor_connection(connection)
+
+def start_transfer(buddy, file_name, title, description, mime_type):
+ outgoing_file_transfer = OutgoingFileTransfer(buddy, file_name, title,
+ description, mime_type)
+ new_file_transfer.send(None, file_transfer=outgoing_file_transfer)
+
+def file_transfer_available():
+ conn_watcher = connection_watcher.get_instance()
+ for connection in conn_watcher.get_connections():
+
+ properties_iface = connection[dbus.PROPERTIES_IFACE]
+ properties = properties_iface.GetAll(CONNECTION_INTERFACE_REQUESTS)
+ classes = properties['RequestableChannelClasses']
+ for prop, allowed_prop in classes:
+
+ channel_type = prop.get(CHANNEL + '.ChannelType', '')
+ target_handle_type = prop.get(CHANNEL + '.TargetHandleType', '')
+
+ if len(prop) == 2 and \
+ channel_type == CHANNEL_TYPE_FILE_TRANSFER and \
+ target_handle_type == CONNECTION_HANDLE_TYPE_CONTACT:
+ return True
+
+ return False
+
+new_file_transfer = dispatch.Signal()
+
+if __name__ == '__main__':
+ import tempfile
+
+ input_stream = gio.File('/home/tomeu/isos/Soas2-200904031934.iso').read()
+ output_stream = gio.File(tempfile.mkstemp()[1]).append_to()
+
+ # TODO: Use splice_async when it gets implemented
+ splicer = StreamSplicer(input_stream, output_stream)
+ splicer.start()
+
+ loop = gobject.MainLoop()
+ loop.run()
+
diff --git a/shell/src/jarabe/model/friends.py b/shell/src/jarabe/model/friends.py
new file mode 100644
index 0000000..b7bf7f1
--- /dev/null
+++ b/shell/src/jarabe/model/friends.py
@@ -0,0 +1,122 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+from ConfigParser import ConfigParser
+
+import gobject
+import dbus
+
+from jarabe.model.buddy import BuddyModel
+from sugar import env
+
+class Friends(gobject.GObject):
+ __gsignals__ = {
+ 'friend-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'friend-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([str]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._friends = {}
+ self._path = os.path.join(env.get_profile_path(), 'friends')
+
+ self.load()
+
+ def has_buddy(self, buddy):
+ return self._friends.has_key(buddy.get_key())
+
+ def add_friend(self, buddy_info):
+ self._friends[buddy_info.get_key()] = buddy_info
+ self.emit('friend-added', buddy_info)
+
+ def make_friend(self, buddy):
+ if not self.has_buddy(buddy):
+ self.add_friend(buddy)
+ self.save()
+
+ def remove(self, buddy_info):
+ del self._friends[buddy_info.get_key()]
+ self.save()
+ self.emit('friend-removed', buddy_info.get_key())
+
+ def __iter__(self):
+ return self._friends.values().__iter__()
+
+ def load(self):
+ cp = ConfigParser()
+
+ try:
+ success = cp.read([self._path])
+ if success:
+ for key in cp.sections():
+ # HACK: don't screw up on old friends files
+ if len(key) < 20:
+ continue
+ buddy = BuddyModel(key=key, nick=cp.get(key, 'nick'))
+ self.add_friend(buddy)
+ except Exception:
+ logging.exception('Error parsing friends file')
+
+ def save(self):
+ cp = ConfigParser()
+
+ for friend in self:
+ section = friend.get_key()
+ cp.add_section(section)
+ cp.set(section, 'nick', friend.get_nick())
+ cp.set(section, 'color', friend.get_color().to_string())
+
+ fileobject = open(self._path, 'w')
+ cp.write(fileobject)
+ fileobject.close()
+
+ self._sync_friends()
+
+ def _sync_friends(self):
+ # XXX: temporary hack
+ # remove this when the shell service has a D-Bus API for buddies
+
+ def friends_synced():
+ pass
+
+ def friends_synced_error(e):
+ logging.error('Error asking presence service to sync friends: %s',
+ e)
+
+ keys = []
+ for friend in self:
+ keys.append(friend.get_key())
+
+ bus = dbus.SessionBus()
+ ps = bus.get_object('org.laptop.Sugar.Presence',
+ '/org/laptop/Sugar/Presence')
+ psi = dbus.Interface(ps, 'org.laptop.Sugar.Presence')
+ psi.SyncFriends(keys,
+ reply_handler=friends_synced,
+ error_handler=friends_synced_error)
+
+_model = None
+
+def get_model():
+ global _model
+ if _model is None:
+ _model = Friends()
+ return _model
diff --git a/shell/src/jarabe/model/invites.py b/shell/src/jarabe/model/invites.py
new file mode 100644
index 0000000..a386d30
--- /dev/null
+++ b/shell/src/jarabe/model/invites.py
@@ -0,0 +1,239 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from functools import partial
+
+import gobject
+import dbus
+from telepathy.interfaces import CHANNEL, \
+ CHANNEL_DISPATCHER, \
+ CHANNEL_DISPATCH_OPERATION, \
+ CHANNEL_TYPE_CONTACT_LIST, \
+ CHANNEL_TYPE_DBUS_TUBE, \
+ CHANNEL_TYPE_STREAMED_MEDIA, \
+ CHANNEL_TYPE_STREAM_TUBE, \
+ CHANNEL_TYPE_TEXT, \
+ CLIENT
+from telepathy.constants import HANDLE_TYPE_ROOM
+
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.model import telepathyclient
+from jarabe.model import bundleregistry
+from jarabe.model import neighborhood
+from jarabe.journal import misc
+
+CONNECTION_INTERFACE_ACTIVITY_PROPERTIES = \
+ 'org.laptop.Telepathy.ActivityProperties'
+
+
+class ActivityInvite(object):
+ """Invitation to a shared activity."""
+ def __init__(self, dispatch_operation_path, handle, handler,
+ activity_properties):
+ self.dispatch_operation_path = dispatch_operation_path
+ self._handle = handle
+ self._handler = handler
+
+ if activity_properties is not None:
+ self._activity_properties = activity_properties
+ else:
+ self._activity_properties = {}
+
+ def get_bundle_id(self):
+ if CLIENT in self._handler:
+ return self._handler[len(CLIENT + '.'):]
+ else:
+ return None
+
+ def get_color(self):
+ color = self._activity_properties.get('color', None)
+ return XoColor(color)
+
+ def join(self):
+ logging.error('ActivityInvite.join handler %r', self._handler)
+
+ registry = bundleregistry.get_registry()
+ bundle_id = self.get_bundle_id()
+ bundle = registry.get_bundle(bundle_id)
+ if bundle is None:
+ self._call_handle_with()
+ else:
+ bus = dbus.SessionBus()
+ bus.add_signal_receiver(self.__name_owner_changed_cb,
+ 'NameOwnerChanged',
+ 'org.freedesktop.DBus',
+ arg0=self._handler)
+
+ model = neighborhood.get_model()
+ activity_id = model.get_activity_by_room(self._handle).activity_id
+ misc.launch(bundle, color=self.get_color(), invited=True,
+ activity_id=activity_id)
+
+ def __name_owner_changed_cb(self, name, old_owner, new_owner):
+ logging.debug('ActivityInvite.__name_owner_changed_cb %r %r %r', name,
+ new_owner, old_owner)
+ if name == self._handler and new_owner and not old_owner:
+ self._call_handle_with()
+
+ def _call_handle_with(self):
+ bus = dbus.Bus()
+ obj = bus.get_object(CHANNEL_DISPATCHER, self.dispatch_operation_path)
+ dispatch_operation = dbus.Interface(obj, CHANNEL_DISPATCH_OPERATION)
+ dispatch_operation.HandleWith(self._handler,
+ reply_handler=self.__handle_with_reply_cb,
+ error_handler=self.__handle_with_reply_cb)
+
+ def __handle_with_reply_cb(self, error=None):
+ if error is not None:
+ raise error
+ else:
+ logging.debug('__handle_with_reply_cb')
+
+class Invites(gobject.GObject):
+ __gsignals__ = {
+ 'invite-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'invite-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._dispatch_operations = {}
+
+ client_handler = telepathyclient.get_instance()
+ client_handler.got_dispatch_operation.connect(
+ self.__got_dispatch_operation_cb)
+
+ def __got_dispatch_operation_cb(self, **kwargs):
+ logging.debug('__got_dispatch_operation_cb')
+ dispatch_operation_path = kwargs['dispatch_operation_path']
+ channel_path, channel_properties = kwargs['channels'][0]
+ properties = kwargs['properties']
+ channel_type = channel_properties[CHANNEL + '.ChannelType']
+ handle_type = channel_properties[CHANNEL + '.TargetHandleType']
+ handle = channel_properties[CHANNEL + '.TargetHandle']
+
+ if handle_type == HANDLE_TYPE_ROOM and \
+ channel_type == CHANNEL_TYPE_TEXT:
+ logging.debug('May be an activity, checking its properties')
+ connection_path = properties[CHANNEL_DISPATCH_OPERATION +
+ '.Connection']
+ connection_name = connection_path.replace('/', '.')[1:]
+
+ bus = dbus.Bus()
+ connection = bus.get_object(connection_name, connection_path)
+ connection.GetProperties(
+ channel_properties[CHANNEL + '.TargetHandle'],
+ dbus_interface=CONNECTION_INTERFACE_ACTIVITY_PROPERTIES,
+ reply_handler=partial(self.__get_properties_cb,
+ handle,
+ dispatch_operation_path),
+ error_handler=partial(self.__error_handler_cb,
+ handle,
+ channel_properties,
+ dispatch_operation_path))
+ else:
+ self._dispatch_non_sugar_invitation(channel_path,
+ channel_properties,
+ dispatch_operation_path)
+
+ def __get_properties_cb(self, handle, dispatch_operation_path, properties):
+ logging.debug('__get_properties_cb %r', properties)
+ handler = '%s.%s' % (CLIENT, properties['type'])
+ self._add_invite(dispatch_operation_path, handle, handler, properties)
+
+ def __error_handler_cb(self, handle, channel_properties,
+ dispatch_operation_path, error):
+ logging.debug('__error_handler_cb %r', error)
+ exception_name = 'org.freedesktop.Telepathy.Error.NotAvailable'
+ if error.get_dbus_name() == exception_name:
+ self._dispatch_non_sugar_invitation(handle,
+ channel_properties,
+ dispatch_operation_path)
+ else:
+ raise error
+
+ def _dispatch_non_sugar_invitation(self, handle, channel_properties,
+ dispatch_operation_path):
+ handler = None
+ channel_type = channel_properties[CHANNEL + '.ChannelType']
+ if channel_type == CHANNEL_TYPE_CONTACT_LIST:
+ self._handle_with(dispatch_operation_path, CLIENT + '.Sugar')
+ elif channel_type == CHANNEL_TYPE_TEXT:
+ handler = CLIENT + '.org.laptop.Chat'
+ elif channel_type == CHANNEL_TYPE_STREAMED_MEDIA:
+ handler = CLIENT + '.org.laptop.VideoChat'
+ elif channel_type == CHANNEL_TYPE_DBUS_TUBE:
+ handler = channel_properties[CHANNEL_TYPE_DBUS_TUBE +
+ '.ServiceName']
+ elif channel_type == CHANNEL_TYPE_STREAM_TUBE:
+ handler = channel_properties[CHANNEL_TYPE_STREAM_TUBE + '.Service']
+ else:
+ self._handle_with(dispatch_operation_path, '')
+
+ if handler is not None:
+ logging.debug('Adding an invite from a non-Sugar client')
+ self._add_invite(dispatch_operation_path, handle, handler)
+
+ def _handle_with(self, dispatch_operation_path, handler):
+ logging.debug('_handle_with %r %r', dispatch_operation_path, handler)
+ bus = dbus.Bus()
+ obj = bus.get_object(CHANNEL_DISPATCHER, dispatch_operation_path)
+ dispatch_operation = dbus.Interface(obj, CHANNEL_DISPATCH_OPERATION)
+ dispatch_operation.HandleWith(handler,
+ reply_handler=self.__handle_with_reply_cb,
+ error_handler=self.__handle_with_reply_cb)
+
+ def __handle_with_reply_cb(self, error=None):
+ if error is not None:
+ logging.error('__handle_with_reply_cb %r', error)
+ else:
+ logging.debug('__handle_with_reply_cb')
+
+ def _add_invite(self, dispatch_operation_path, handle, handler,
+ activity_properties=None):
+ logging.debug('_add_invite %r %r %r', dispatch_operation_path, handle,
+ handler)
+ if dispatch_operation_path in self._dispatch_operations:
+ # there is no point to have more than one invite for the same
+ # dispatch operation
+ return
+
+ invite = ActivityInvite(dispatch_operation_path, handle, handler,
+ activity_properties)
+ self._dispatch_operations[dispatch_operation_path] = invite
+ self.emit('invite-added', invite)
+
+ def remove_invite(self, invite):
+ del self._dispatch_operations[invite.dispatch_operation_path]
+ self.emit('invite-removed', invite)
+
+ def __iter__(self):
+ return self._dispatch_operations.values().__iter__()
+
+
+_instance = None
+
+def get_instance():
+ global _instance
+ if not _instance:
+ _instance = Invites()
+ return _instance
diff --git a/shell/src/jarabe/model/mimeregistry.py b/shell/src/jarabe/model/mimeregistry.py
new file mode 100644
index 0000000..537f6f3
--- /dev/null
+++ b/shell/src/jarabe/model/mimeregistry.py
@@ -0,0 +1,49 @@
+# Copyright (C) 2009 Aleksey Lim
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import re
+
+import gconf
+
+
+_DEFAULTS_KEY = '/desktop/sugar/journal/defaults'
+_GCONF_INVALID_CHARS = re.compile('[^a-zA-Z0-9-_/.]')
+_instance = None
+
+
+class MimeRegistry(object):
+
+ def __init__(self):
+ # TODO move here all mime_type related code from jarabe modules
+ self._gconf = gconf.client_get_default()
+
+ def get_default_activity(self, mime_type):
+ return self._gconf.get_string(_key_name(mime_type))
+
+ def set_default_activity(self, mime_type, bundle_id):
+ self._gconf.set_string(_key_name(mime_type), bundle_id)
+
+
+def get_registry():
+ global _instance
+ if _instance is None:
+ _instance = MimeRegistry()
+ return _instance
+
+
+def _key_name(mime_type):
+ mime_type = _GCONF_INVALID_CHARS.sub('_', mime_type)
+ return '%s/%s' % (_DEFAULTS_KEY, mime_type)
diff --git a/shell/src/jarabe/model/neighborhood.py b/shell/src/jarabe/model/neighborhood.py
new file mode 100644
index 0000000..90531a6
--- /dev/null
+++ b/shell/src/jarabe/model/neighborhood.py
@@ -0,0 +1,863 @@
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from functools import partial
+
+import gobject
+import gconf
+import dbus
+from dbus import PROPERTIES_IFACE
+from telepathy.interfaces import ACCOUNT, \
+ ACCOUNT_MANAGER, \
+ CHANNEL, \
+ CHANNEL_INTERFACE_GROUP, \
+ CHANNEL_TYPE_CONTACT_LIST, \
+ CONNECTION, \
+ CONNECTION_INTERFACE_ALIASING, \
+ CONNECTION_INTERFACE_CONTACTS, \
+ CONNECTION_INTERFACE_REQUESTS, \
+ CONNECTION_INTERFACE_SIMPLE_PRESENCE
+from telepathy.constants import HANDLE_TYPE_LIST, \
+ CONNECTION_PRESENCE_TYPE_OFFLINE, \
+ CONNECTION_STATUS_CONNECTED, \
+ CONNECTION_STATUS_DISCONNECTED
+from telepathy.client import Connection, Channel
+
+from sugar.graphics.xocolor import XoColor
+from sugar.profile import get_profile
+
+from jarabe.model.buddy import BuddyModel, get_owner_instance
+from jarabe.model import bundleregistry
+
+ACCOUNT_MANAGER_SERVICE = 'org.freedesktop.Telepathy.AccountManager'
+ACCOUNT_MANAGER_PATH = '/org/freedesktop/Telepathy/AccountManager'
+CHANNEL_DISPATCHER_SERVICE = 'org.freedesktop.Telepathy.ChannelDispatcher'
+CHANNEL_DISPATCHER_PATH = '/org/freedesktop/Telepathy/ChannelDispatcher'
+SUGAR_CLIENT_SERVICE = 'org.freedesktop.Telepathy.Client.Sugar'
+SUGAR_CLIENT_PATH = '/org/freedesktop/Telepathy/Client/Sugar'
+
+CONNECTION_INTERFACE_BUDDY_INFO = 'org.laptop.Telepathy.BuddyInfo'
+CONNECTION_INTERFACE_ACTIVITY_PROPERTIES = \
+ 'org.laptop.Telepathy.ActivityProperties'
+
+class ActivityModel(gobject.GObject):
+ __gsignals__ = {
+ 'current-buddy-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'current-buddy-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'buddy-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'buddy-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ }
+ def __init__(self, activity_id, room_handle):
+ gobject.GObject.__init__(self)
+
+ self.activity_id = activity_id
+ self.room_handle = room_handle
+ self._bundle = None
+ self._color = None
+ self._private = True
+ self._name = None
+ self._current_buddies = []
+ self._buddies = []
+
+ def get_color(self):
+ return self._color
+
+ def set_color(self, color):
+ self._color = color
+
+ color = gobject.property(type=object, getter=get_color, setter=set_color)
+
+ def get_bundle(self):
+ return self._bundle
+
+ def set_bundle(self, bundle):
+ self._bundle = bundle
+
+ bundle = gobject.property(type=object, getter=get_bundle, setter=set_bundle)
+
+ def get_name(self):
+ return self._name
+
+ def set_name(self, name):
+ self._name = name
+
+ name = gobject.property(type=object, getter=get_name, setter=set_name)
+
+ def is_private(self):
+ return self._private
+
+ def set_private(self, private):
+ self._private = private
+
+ private = gobject.property(type=object, getter=is_private,
+ setter=set_private)
+
+ def get_buddies(self):
+ return self._buddies
+
+ def add_buddy(self, buddy):
+ self._buddies.append(buddy)
+ self.notify('buddies')
+ self.emit('buddy-added', buddy)
+
+ def remove_buddy(self, buddy):
+ self._buddies.remove(buddy)
+ self.notify('buddies')
+ self.emit('buddy-removed', buddy)
+
+ buddies = gobject.property(type=object, getter=get_buddies)
+
+ def get_current_buddies(self):
+ return self._current_buddies
+
+ def add_current_buddy(self, buddy):
+ self._current_buddies.append(buddy)
+ self.notify('current-buddies')
+ self.emit('current-buddy-added', buddy)
+
+ def remove_current_buddy(self, buddy):
+ self._current_buddies.remove(buddy)
+ self.notify('current-buddies')
+ self.emit('current-buddy-removed', buddy)
+
+ current_buddies = gobject.property(type=object, getter=get_current_buddies)
+
+class _Account(gobject.GObject):
+ __gsignals__ = {
+ 'activity-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object, object])),
+ 'activity-updated': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object, object])),
+ 'activity-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'buddy-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object, object, object])),
+ 'buddy-updated': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object, object])),
+ 'buddy-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'buddy-joined-activity': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object, object])),
+ 'buddy-left-activity': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object, object])),
+ 'current-activity-updated': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object, object])),
+ 'connected': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ 'disconnected': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ }
+
+ def __init__(self, account_path):
+ gobject.GObject.__init__(self)
+
+ self.object_path = account_path
+
+ self._connection = None
+ self._buddy_handles = {}
+ self._activity_handles = {}
+ self._self_handle = None
+
+ self._buddies_per_activity = {}
+ self._activities_per_buddy = {}
+
+ self._start_listening()
+
+ def _start_listening(self):
+ bus = dbus.Bus()
+ obj = bus.get_object(ACCOUNT_MANAGER_SERVICE, self.object_path)
+ obj.Get(ACCOUNT, 'Connection',
+ reply_handler=self.__got_connection_cb,
+ error_handler=partial(self.__error_handler_cb,
+ 'Account.GetConnection'))
+ obj.connect_to_signal(
+ 'AccountPropertyChanged', self.__account_property_changed_cb)
+
+ def __error_handler_cb(self, function_name, error):
+ raise RuntimeError('Error when calling %s: %s' % (function_name, error))
+
+ def __got_connection_cb(self, connection_path):
+ logging.debug('_Account.__got_connection_cb %r', connection_path)
+
+ if connection_path == '/':
+ # Account has no connection, wait until it has one.
+ return
+
+ self._prepare_connection(connection_path)
+
+ def __account_property_changed_cb(self, properties):
+ logging.debug('_Account.__account_property_changed_cb %r %r %r',
+ self.object_path, properties.get('Connection', None),
+ self._connection)
+ if 'Connection' not in properties:
+ return
+ if properties['Connection'] == '/':
+ self._connection = None
+ elif self._connection is None:
+ self._prepare_connection(properties['Connection'])
+
+ def _prepare_connection(self, connection_path):
+ connection_name = connection_path.replace('/', '.')[1:]
+
+ self._connection = Connection(connection_name, connection_path,
+ ready_handler=self.__connection_ready_cb)
+
+ def __connection_ready_cb(self, connection):
+ logging.debug('_Account.__connection_ready_cb %r',
+ connection.object_path)
+ connection.connect_to_signal('StatusChanged',
+ self.__status_changed_cb)
+
+ connection[PROPERTIES_IFACE].Get(CONNECTION,
+ 'Status',
+ reply_handler=self.__get_status_cb,
+ error_handler=partial(self.__error_handler_cb,
+ 'Connection.GetStatus'))
+
+ def __get_status_cb(self, status):
+ logging.debug('_Account.__get_status_cb %r %r',
+ self._connection.object_path, status)
+ self._update_status(status)
+
+ def __status_changed_cb(self, status, reason):
+ logging.debug('_Account.__status_changed_cb %r %r', status, reason)
+ self._update_status(status)
+
+ def _update_status(self, status):
+ if status == CONNECTION_STATUS_CONNECTED:
+ self._connection[PROPERTIES_IFACE].Get(CONNECTION,
+ 'SelfHandle',
+ reply_handler=self.__get_self_handle_cb,
+ error_handler=partial(self.__error_handler_cb,
+ 'Connection.GetSelfHandle'))
+ self.emit('connected')
+ else:
+ for contact_handle, contact_id in self._buddy_handles.items():
+ self.emit('buddy-removed', contact_id)
+
+ for room_handle, activity_id in self._activity_handles.items():
+ self.emit('activity-removed', activity_id)
+
+ self._buddy_handles = {}
+ self._activity_handles = {}
+ self._buddies_per_activity = {}
+ self._activities_per_buddy = {}
+
+ self.emit('disconnected')
+
+ if status == CONNECTION_STATUS_DISCONNECTED:
+ self._connection = None
+
+ def __get_self_handle_cb(self, self_handle):
+ self._self_handle = self_handle
+
+ connection = self._connection[CONNECTION_INTERFACE_ALIASING]
+ connection.connect_to_signal('AliasesChanged',
+ self.__aliases_changed_cb)
+
+ connection = self._connection[CONNECTION_INTERFACE_SIMPLE_PRESENCE]
+ connection.connect_to_signal('PresencesChanged',
+ self.__presences_changed_cb)
+
+ if CONNECTION_INTERFACE_BUDDY_INFO in self._connection:
+ connection = self._connection[CONNECTION_INTERFACE_BUDDY_INFO]
+ connection.connect_to_signal('PropertiesChanged',
+ self.__buddy_info_updated_cb,
+ byte_arrays=True)
+
+ connection.connect_to_signal('ActivitiesChanged',
+ self.__buddy_activities_changed_cb)
+
+ connection.connect_to_signal('CurrentActivityChanged',
+ self.__current_activity_changed_cb)
+ else:
+ logging.warning('Connection %s does not support OLPC buddy '
+ 'properties', self._connection.object_path)
+
+ if CONNECTION_INTERFACE_ACTIVITY_PROPERTIES in self._connection:
+ connection = self._connection[
+ CONNECTION_INTERFACE_ACTIVITY_PROPERTIES]
+ connection.connect_to_signal(
+ 'ActivityPropertiesChanged',
+ self.__activity_properties_changed_cb)
+ else:
+ logging.warning('Connection %s does not support OLPC activity '
+ 'properties', self._connection.object_path)
+
+ properties = {
+ CHANNEL + '.ChannelType': CHANNEL_TYPE_CONTACT_LIST,
+ CHANNEL + '.TargetHandleType': HANDLE_TYPE_LIST,
+ CHANNEL + '.TargetID': 'subscribe',
+ }
+ properties = dbus.Dictionary(properties, signature='sv')
+ connection = self._connection[CONNECTION_INTERFACE_REQUESTS]
+ is_ours, channel_path, properties = \
+ connection.EnsureChannel(properties)
+
+ channel = Channel(self._connection.service_name, channel_path)
+ channel[CHANNEL_INTERFACE_GROUP].connect_to_signal(
+ 'MembersChanged', self.__members_changed_cb)
+
+ channel[PROPERTIES_IFACE].Get(CHANNEL_INTERFACE_GROUP,
+ 'Members',
+ reply_handler=self.__get_members_ready_cb,
+ error_handler=partial(self.__error_handler_cb,
+ 'Connection.GetMembers'))
+
+ def __aliases_changed_cb(self, aliases):
+ logging.debug('_Account.__aliases_changed_cb')
+ for handle, alias in aliases:
+ if handle in self._buddy_handles:
+ logging.debug('Got handle %r with nick %r, going to update',
+ handle, alias)
+
+ def __presences_changed_cb(self, presences):
+ logging.debug('_Account.__presences_changed_cb %r', presences)
+ for handle, presence in presences.iteritems():
+ if handle in self._buddy_handles:
+ presence_type, status_, message_ = presence
+ if presence_type == CONNECTION_PRESENCE_TYPE_OFFLINE:
+ del self._buddy_handles[handle]
+ self.emit('buddy-removed', handle)
+
+ def __buddy_info_updated_cb(self, handle, properties):
+ logging.debug('_Account.__buddy_info_updated_cb %r %r', handle,
+ properties)
+
+ def __current_activity_changed_cb(self, contact_handle, activity_id,
+ room_handle):
+ logging.debug('_Account.__current_activity_changed_cb %r %r %r',
+ contact_handle, activity_id, room_handle)
+ if contact_handle in self._buddy_handles:
+ contact_id = self._buddy_handles[contact_handle]
+ if not activity_id and room_handle:
+ activity_id = self._activity_handles.get(room_handle, '')
+ self.emit('current-activity-updated', contact_id, activity_id)
+
+ def __get_current_activity_cb(self, contact_handle, activity_id,
+ room_handle):
+ logging.debug('_Account.__get_current_activity_cb %r %r %r',
+ contact_handle, activity_id, room_handle)
+ contact_id = self._buddy_handles[contact_handle]
+ self.emit('current-activity-updated', contact_id, activity_id)
+
+ def __buddy_activities_changed_cb(self, buddy_handle, activities):
+ logging.debug('_Account.__buddy_activities_changed_cb %r %r',
+ buddy_handle, activities)
+ self._update_buddy_activities(buddy_handle, activities)
+
+ def _update_buddy_activities(self, buddy_handle, activities):
+ logging.debug('_Account._update_buddy_activities')
+ if not buddy_handle in self._buddy_handles:
+ self._buddy_handles[buddy_handle] = None
+
+ if not buddy_handle in self._activities_per_buddy:
+ self._activities_per_buddy[buddy_handle] = set()
+
+ for activity_id, room_handle in activities:
+ if room_handle not in self._activity_handles:
+ self._activity_handles[room_handle] = activity_id
+ self.emit('activity-added', room_handle, activity_id)
+
+ connection = self._connection[
+ CONNECTION_INTERFACE_ACTIVITY_PROPERTIES]
+ connection.GetProperties(room_handle,
+ reply_handler=partial(self.__get_properties_cb,
+ room_handle),
+ error_handler=partial(self.__error_handler_cb,
+ 'ActivityProperties.GetProperties'))
+
+ # Sometimes we'll get CurrentActivityChanged before we get to
+ # know about the activity so we miss the event. In that case,
+ # request again the current activity for this buddy.
+ connection = self._connection[CONNECTION_INTERFACE_BUDDY_INFO]
+ connection.GetCurrentActivity(
+ buddy_handle,
+ reply_handler=partial(self.__get_current_activity_cb,
+ buddy_handle),
+ error_handler=partial(self.__error_handler_cb,
+ 'BuddyInfo.GetCurrentActivity'))
+
+ if not activity_id in self._buddies_per_activity:
+ self._buddies_per_activity[activity_id] = set()
+ self._buddies_per_activity[activity_id].add(buddy_handle)
+ if activity_id not in self._activities_per_buddy[buddy_handle]:
+ self._activities_per_buddy[buddy_handle].add(activity_id)
+ if self._buddy_handles[buddy_handle] is not None:
+ self.emit('buddy-joined-activity',
+ self._buddy_handles[buddy_handle],
+ activity_id)
+
+ current_activity_ids = \
+ [activity_id for activity_id, room_handle in activities]
+ for activity_id in self._activities_per_buddy[buddy_handle].copy():
+ if not activity_id in current_activity_ids:
+ self._remove_buddy_from_activity(buddy_handle, activity_id)
+
+ def __get_properties_cb(self, room_handle, properties):
+ logging.debug('_Account.__get_properties_cb %r %r', room_handle,
+ properties)
+ if properties:
+ self._update_activity(room_handle, properties)
+
+ def _remove_buddy_from_activity(self, buddy_handle, activity_id):
+ if buddy_handle in self._buddies_per_activity[activity_id]:
+ self._buddies_per_activity[activity_id].remove(buddy_handle)
+
+ if activity_id in self._activities_per_buddy[buddy_handle]:
+ self._activities_per_buddy[buddy_handle].remove(activity_id)
+
+ if self._buddy_handles[buddy_handle] is not None:
+ self.emit('buddy-left-activity',
+ self._buddy_handles[buddy_handle],
+ activity_id)
+
+ if not self._buddies_per_activity[activity_id]:
+ del self._buddies_per_activity[activity_id]
+
+ for room_handle in self._activity_handles.copy():
+ if self._activity_handles[room_handle] == activity_id:
+ del self._activity_handles[room_handle]
+ break
+
+ self.emit('activity-removed', activity_id)
+
+ def __activity_properties_changed_cb(self, room_handle, properties):
+ logging.debug('_Account.__activity_properties_changed_cb %r %r',
+ room_handle, properties)
+ self._update_activity(room_handle, properties)
+
+ def _update_activity(self, room_handle, properties):
+ if room_handle in self._activity_handles:
+ self.emit('activity-updated', self._activity_handles[room_handle],
+ properties)
+ else:
+ logging.debug('_Account.__activity_properties_changed_cb unknown '
+ 'activity')
+ # We don't get ActivitiesChanged for the owner of the connection,
+ # so we query for its activities in order to find out.
+ if CONNECTION_INTERFACE_BUDDY_INFO in self._connection:
+ handle = self._self_handle
+ connection = self._connection[CONNECTION_INTERFACE_BUDDY_INFO]
+ connection.GetActivities(
+ handle,
+ reply_handler=partial(self.__got_activities_cb, handle),
+ error_handler=partial(self.__error_handler_cb,
+ 'BuddyInfo.Getactivities'))
+
+ def __members_changed_cb(self, message, added, removed, local_pending,
+ remote_pending, actor, reason):
+ self._add_buddy_handles(added)
+
+ def __get_members_ready_cb(self, handles):
+ logging.debug('_Account.__get_members_ready_cb %r', handles)
+ if not handles:
+ return
+
+ self._add_buddy_handles(handles)
+
+ def _add_buddy_handles(self, handles):
+ logging.debug('_Account._add_buddy_handles %r', handles)
+ interfaces = [CONNECTION, CONNECTION_INTERFACE_ALIASING]
+ self._connection[CONNECTION_INTERFACE_CONTACTS].GetContactAttributes(
+ handles, interfaces, False,
+ reply_handler=self.__get_contact_attributes_cb,
+ error_handler=partial(self.__error_handler_cb,
+ 'Contacts.GetContactAttributes'))
+
+ def __got_buddy_info_cb(self, handle, nick, properties):
+ logging.debug('_Account.__got_buddy_info_cb %r', properties)
+ self.emit('buddy-added', self._buddy_handles[handle], nick,
+ properties.get('key', None))
+ self.emit('buddy-updated', self._buddy_handles[handle], properties)
+
+ def __get_contact_attributes_cb(self, attributes):
+ logging.debug('_Account.__get_contact_attributes_cb %r',
+ attributes.keys())
+
+ for handle in attributes.keys():
+ nick = attributes[handle][CONNECTION_INTERFACE_ALIASING + '/alias']
+
+ if handle in self._buddy_handles and \
+ not self._buddy_handles[handle] is None:
+ logging.debug('Got handle %r with nick %r, going to update',
+ handle, nick)
+ self.emit('buddy-updated', self._buddy_handles[handle],
+ attributes[handle])
+ else:
+ logging.debug('Got handle %r with nick %r, going to add',
+ handle, nick)
+
+ contact_id = attributes[handle][CONNECTION + '/contact-id']
+ self._buddy_handles[handle] = contact_id
+
+ if CONNECTION_INTERFACE_BUDDY_INFO in self._connection:
+ connection = \
+ self._connection[CONNECTION_INTERFACE_BUDDY_INFO]
+
+ connection.GetProperties(
+ handle,
+ reply_handler=partial(self.__got_buddy_info_cb, handle,
+ nick),
+ error_handler=partial(self.__error_handler_cb,
+ 'BuddyInfo.GetProperties'),
+ byte_arrays=True)
+
+ connection.GetActivities(
+ handle,
+ reply_handler=partial(self.__got_activities_cb, handle),
+ error_handler=partial(self.__error_handler_cb,
+ 'BuddyInfo.GetActivities'))
+
+ connection.GetCurrentActivity(
+ handle,
+ reply_handler=partial(self.__get_current_activity_cb,
+ handle),
+ error_handler=partial(self.__error_handler_cb,
+ 'BuddyInfo.GetCurrentActivity'))
+ else:
+ self.emit('buddy-added', contact_id, nick, None)
+
+ def __got_activities_cb(self, buddy_handle, activities):
+ logging.debug('_Account.__got_activities_cb %r %r', buddy_handle,
+ activities)
+ self._update_buddy_activities(buddy_handle, activities)
+
+ def enable(self):
+ logging.debug('_Account.enable %s', self.object_path)
+ self._set_enabled(True)
+
+ def disable(self):
+ logging.debug('_Account.disable %s', self.object_path)
+ self._set_enabled(False)
+ self._connection = None
+
+ def _set_enabled(self, value):
+ bus = dbus.Bus()
+ obj = bus.get_object(ACCOUNT_MANAGER_SERVICE, self.object_path)
+ obj.Set(ACCOUNT, 'Enabled', value,
+ reply_handler=self.__set_enabled_cb,
+ error_handler=partial(self.__error_handler_cb,
+ 'Account.SetEnabled'),
+ dbus_interface='org.freedesktop.DBus.Properties')
+
+ def __set_enabled_cb(self):
+ logging.debug('_Account.__set_enabled_cb success')
+
+class Neighborhood(gobject.GObject):
+ __gsignals__ = {
+ 'activity-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'activity-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'buddy-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object])),
+ 'buddy-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([object]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._buddies = {None: get_owner_instance()}
+ self._activities = {}
+ self._link_local_account = None
+ self._server_account = None
+
+ bus = dbus.Bus()
+ obj = bus.get_object(ACCOUNT_MANAGER_SERVICE, ACCOUNT_MANAGER_PATH)
+ account_manager = dbus.Interface(obj, ACCOUNT_MANAGER)
+ account_manager.Get(ACCOUNT_MANAGER, 'ValidAccounts',
+ dbus_interface=PROPERTIES_IFACE,
+ reply_handler=self.__got_accounts_cb,
+ error_handler=self.__error_handler_cb)
+
+ def __got_accounts_cb(self, account_paths):
+ self._link_local_account = \
+ self._ensure_link_local_account(account_paths)
+ self._connect_to_account(self._link_local_account)
+
+ self._server_account = self._ensure_server_account(account_paths)
+ self._connect_to_account(self._server_account)
+
+ def __error_handler_cb(self, error):
+ raise RuntimeError(error)
+
+ def _connect_to_account(self, account):
+ account.connect('buddy-added', self.__buddy_added_cb)
+ account.connect('buddy-updated', self.__buddy_updated_cb)
+ account.connect('buddy-removed', self.__buddy_removed_cb)
+ account.connect('buddy-joined-activity',
+ self.__buddy_joined_activity_cb)
+ account.connect('buddy-left-activity', self.__buddy_left_activity_cb)
+ account.connect('activity-added', self.__activity_added_cb)
+ account.connect('activity-updated', self.__activity_updated_cb)
+ account.connect('activity-removed', self.__activity_removed_cb)
+ account.connect('current-activity-updated',
+ self.__current_activity_updated_cb)
+ account.connect('connected', self.__account_connected_cb)
+ account.connect('disconnected', self.__account_disconnected_cb)
+
+ def __account_connected_cb(self, account):
+ logging.debug('__account_connected_cb %s', account.object_path)
+ if account == self._server_account:
+ self._link_local_account.disable()
+
+ def __account_disconnected_cb(self, account):
+ logging.debug('__account_disconnected_cb %s', account.object_path)
+ if account == self._server_account:
+ self._link_local_account.enable()
+
+ def _ensure_link_local_account(self, account_paths):
+ for account_path in account_paths:
+ if 'salut' in account_path:
+ logging.debug('Already have a Salut account')
+ account = _Account(account_path)
+ account.enable()
+ return account
+
+ logging.debug('Still dont have a Salut account, creating one')
+
+ client = gconf.client_get_default()
+ nick = client.get_string('/desktop/sugar/user/nick')
+ server = client.get_string('/desktop/sugar/collaboration/jabber_server')
+
+ params = {
+ 'nickname': nick,
+ 'first-name': '',
+ 'last-name': '',
+ 'jid': '%s@%s' % (self._sanitize_nick(nick), server),
+ 'published-name': nick,
+ }
+
+ properties = {
+ 'org.freedesktop.Telepathy.Account.Enabled': True,
+ 'org.freedesktop.Telepathy.Account.Nickname': nick,
+ 'org.freedesktop.Telepathy.Account.ConnectAutomatically': True,
+ }
+
+ bus = dbus.Bus()
+ obj = bus.get_object(ACCOUNT_MANAGER_SERVICE, ACCOUNT_MANAGER_PATH)
+ account_manager = dbus.Interface(obj, ACCOUNT_MANAGER)
+ account_path = account_manager.CreateAccount('salut', 'local-xmpp',
+ 'salut', params,
+ properties)
+ return _Account(account_path)
+
+ def _ensure_server_account(self, account_paths):
+ for account_path in account_paths:
+ if 'gabble' in account_path:
+ logging.debug('Already have a Gabble account')
+ account = _Account(account_path)
+ account.enable()
+ return account
+
+ logging.debug('Still dont have a Gabble account, creating one')
+
+ client = gconf.client_get_default()
+ nick = client.get_string('/desktop/sugar/user/nick')
+ server = client.get_string('/desktop/sugar/collaboration/jabber_server')
+ key_hash = get_profile().privkey_hash
+
+ params = {
+ 'account': '%s@%s' % (self._sanitize_nick(nick), server),
+ 'password': key_hash,
+ 'server': server,
+ 'resource': 'sugar',
+ 'require-encryption': True,
+ 'ignore-ssl-errors': True,
+ 'register': True,
+ 'old-ssl': True,
+ 'port': dbus.UInt32(5223),
+ }
+
+ properties = {
+ 'org.freedesktop.Telepathy.Account.Enabled': True,
+ 'org.freedesktop.Telepathy.Account.Nickname': nick,
+ 'org.freedesktop.Telepathy.Account.ConnectAutomatically': True,
+ }
+
+ bus = dbus.Bus()
+ obj = bus.get_object(ACCOUNT_MANAGER_SERVICE, ACCOUNT_MANAGER_PATH)
+ account_manager = dbus.Interface(obj, ACCOUNT_MANAGER)
+ account_path = account_manager.CreateAccount('gabble', 'jabber',
+ 'jabber', params,
+ properties)
+ return _Account(account_path)
+
+ def _sanitize_nick(self, nick):
+ return nick.replace(' ', '_')
+
+ def __buddy_added_cb(self, account, contact_id, nick, key):
+ logging.debug('__buddy_added_cb %r', contact_id)
+
+ if contact_id in self._buddies:
+ logging.debug('__buddy_added_cb buddy already tracked')
+ return
+
+ buddy = BuddyModel(
+ nick=nick,
+ account=account.object_path,
+ contact_id=contact_id,
+ key=key)
+ self._buddies[contact_id] = buddy
+
+ self.emit('buddy-added', buddy)
+
+ def __buddy_updated_cb(self, account, contact_id, properties):
+ logging.debug('__buddy_updated_cb %r %r', contact_id, properties)
+ if contact_id not in self._buddies:
+ logging.debug('__buddy_updated_cb Unknown buddy with contact_id %r',
+ contact_id)
+ return
+
+ buddy = self._buddies[contact_id]
+ if 'color' in properties:
+ buddy.props.color = XoColor(properties['color'])
+
+ def __buddy_removed_cb(self, account, contact_id):
+ logging.debug('Neighborhood.__buddy_removed_cb %r', contact_id)
+ if contact_id not in self._buddies:
+ logging.debug('Neighborhood.__buddy_removed_cb Unknown buddy with '
+ 'contact_id %r', contact_id)
+ return
+
+ buddy = self._buddies[contact_id]
+ del self._buddies[contact_id]
+ self.emit('buddy-removed', buddy)
+
+ def __activity_added_cb(self, account, room_handle, activity_id):
+ logging.debug('__activity_added_cb %r %r', room_handle, activity_id)
+ if activity_id in self._activities:
+ logging.debug('__activity_added_cb activity already tracked')
+ return
+
+ activity = ActivityModel(activity_id, room_handle)
+ self._activities[activity_id] = activity
+
+ def __activity_updated_cb(self, account, activity_id, properties):
+ logging.debug('__activity_updated_cb %r %r', activity_id, properties)
+ if activity_id not in self._activities:
+ logging.debug('__activity_updated_cb Unknown activity with '
+ 'activity_id %r', activity_id)
+ return
+
+ registry = bundleregistry.get_registry()
+ bundle = registry.get_bundle(properties['type'])
+ if not bundle:
+ logging.warning('Ignoring shared activity we don''t have')
+ return
+
+ activity = self._activities[activity_id]
+
+ is_new = activity.props.bundle is None
+
+ activity.props.color = XoColor(properties['color'])
+ activity.props.bundle = bundle
+ activity.props.name = properties['name']
+ activity.props.private = properties['private']
+
+ if is_new:
+ self.emit('activity-added', activity)
+
+ def __activity_removed_cb(self, account, activity_id):
+ logging.debug('__activity_removed_cb %r', activity_id)
+ if activity_id not in self._activities:
+ logging.debug('Unknown activity with id %s. Already removed?',
+ activity_id)
+ return
+ activity = self._activities[activity_id]
+ del self._activities[activity_id]
+ self.emit('activity-removed', activity)
+
+ def __current_activity_updated_cb(self, account, contact_id, activity_id):
+ logging.debug('__current_activity_updated_cb %r %r', contact_id,
+ activity_id)
+ if contact_id not in self._buddies:
+ logging.debug('__current_activity_updated_cb Unknown buddy with '
+ 'contact_id %r', contact_id)
+ return
+ if activity_id and activity_id not in self._activities:
+ logging.debug('__current_activity_updated_cb Unknown activity with '
+ 'id %s', activity_id)
+ activity_id = ''
+
+ buddy = self._buddies[contact_id]
+ if buddy.props.current_activity is not None:
+ if buddy.props.current_activity.activity_id == activity_id:
+ return
+ buddy.props.current_activity.remove_current_buddy(buddy)
+
+ if activity_id:
+ activity = self._activities[activity_id]
+ buddy.props.current_activity = activity
+ activity.add_current_buddy(buddy)
+ else:
+ buddy.props.current_activity = None
+
+ def __buddy_joined_activity_cb(self, account, contact_id, activity_id):
+ if contact_id not in self._buddies:
+ logging.debug('__buddy_joined_activity_cb Unknown buddy with '
+ 'contact_id %r', contact_id)
+ return
+
+ if activity_id not in self._activities:
+ logging.debug('__buddy_joined_activity_cb Unknown activity with '
+ 'activity_id %r', activity_id)
+ return
+
+ self._activities[activity_id].add_buddy(self._buddies[contact_id])
+
+ def __buddy_left_activity_cb(self, account, contact_id, activity_id):
+ if contact_id not in self._buddies:
+ logging.debug('__buddy_left_activity_cb Unknown buddy with '
+ 'contact_id %r', contact_id)
+ return
+
+ if activity_id not in self._activities:
+ logging.debug('__buddy_left_activity_cb Unknown activity with '
+ 'activity_id %r', activity_id)
+ return
+
+ self._activities[activity_id].remove_buddy(self._buddies[contact_id])
+
+ def get_buddies(self):
+ return self._buddies.values()
+
+ def get_activity(self, activity_id):
+ return self._activities.get(activity_id, None)
+
+ def get_activity_by_room(self, room_handle):
+ for activity in self._activities.values():
+ if activity.room_handle == room_handle:
+ return activity
+ return None
+
+ def get_activities(self):
+ return self._activities.values()
+
+_model = None
+
+def get_model():
+ global _model
+ if _model is None:
+ _model = Neighborhood()
+ return _model
diff --git a/shell/src/jarabe/model/network.py b/shell/src/jarabe/model/network.py
new file mode 100644
index 0000000..cd0d46e
--- /dev/null
+++ b/shell/src/jarabe/model/network.py
@@ -0,0 +1,751 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+# Copyright (C) 2009-2010 One Laptop per Child
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+# Copyright (C) 2010 Plan Ceibal, Daniel Castelo
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import os
+import time
+
+import dbus
+import dbus.service
+import gobject
+import ConfigParser
+import gconf
+
+from sugar import dispatch
+from sugar import env
+from sugar.util import unique_id
+
+DEVICE_TYPE_802_3_ETHERNET = 1
+DEVICE_TYPE_802_11_WIRELESS = 2
+DEVICE_TYPE_GSM_MODEM = 3
+DEVICE_TYPE_802_11_OLPC_MESH = 6
+
+DEVICE_STATE_UNKNOWN = 0
+DEVICE_STATE_UNMANAGED = 1
+DEVICE_STATE_UNAVAILABLE = 2
+DEVICE_STATE_DISCONNECTED = 3
+DEVICE_STATE_PREPARE = 4
+DEVICE_STATE_CONFIG = 5
+DEVICE_STATE_NEED_AUTH = 6
+DEVICE_STATE_IP_CONFIG = 7
+DEVICE_STATE_ACTIVATED = 8
+DEVICE_STATE_FAILED = 9
+
+NM_CONNECTION_TYPE_802_11_WIRELESS = '802-11-wireless'
+NM_CONNECTION_TYPE_GSM = 'gsm'
+
+NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0
+NM_ACTIVE_CONNECTION_STATE_ACTIVATING = 1
+NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2
+
+NM_802_11_AP_FLAGS_NONE = 0x00000000
+NM_802_11_AP_FLAGS_PRIVACY = 0x00000001
+
+NM_802_11_AP_SEC_NONE = 0x00000000
+NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001
+NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002
+NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004
+NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008
+NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010
+NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020
+NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040
+NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080
+NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100
+NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200
+
+NM_802_11_MODE_UNKNOWN = 0
+NM_802_11_MODE_ADHOC = 1
+NM_802_11_MODE_INFRA = 2
+
+NM_802_11_DEVICE_CAP_NONE = 0x00000000
+NM_802_11_DEVICE_CAP_CIPHER_WEP40 = 0x00000001
+NM_802_11_DEVICE_CAP_CIPHER_WEP104 = 0x00000002
+NM_802_11_DEVICE_CAP_CIPHER_TKIP = 0x00000004
+NM_802_11_DEVICE_CAP_CIPHER_CCMP = 0x00000008
+NM_802_11_DEVICE_CAP_WPA = 0x00000010
+NM_802_11_DEVICE_CAP_RSN = 0x00000020
+
+SETTINGS_SERVICE = 'org.freedesktop.NetworkManagerUserSettings'
+
+NM_SETTINGS_PATH = '/org/freedesktop/NetworkManagerSettings'
+NM_SETTINGS_IFACE = 'org.freedesktop.NetworkManagerSettings'
+NM_CONNECTION_IFACE = 'org.freedesktop.NetworkManagerSettings.Connection'
+NM_SECRETS_IFACE = 'org.freedesktop.NetworkManagerSettings.Connection.Secrets'
+NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
+
+GSM_USERNAME_PATH = '/desktop/sugar/network/gsm/username'
+GSM_PASSWORD_PATH = '/desktop/sugar/network/gsm/password'
+GSM_NUMBER_PATH = '/desktop/sugar/network/gsm/number'
+GSM_APN_PATH = '/desktop/sugar/network/gsm/apn'
+GSM_PIN_PATH = '/desktop/sugar/network/gsm/pin'
+GSM_PUK_PATH = '/desktop/sugar/network/gsm/puk'
+
+_nm_settings = None
+_conn_counter = 0
+
+
+def frequency_to_channel(frequency):
+ """Returns the channel matching a given radio channel frequency. If a
+ frequency is not in the dictionary channel 1 will be returned.
+
+ Keyword arguments:
+ frequency -- The radio channel frequency in MHz.
+
+ Return: Channel
+
+ """
+ ftoc = {2412: 1, 2417: 2, 2422: 3, 2427: 4,
+ 2432: 5, 2437: 6, 2442: 7, 2447: 8,
+ 2452: 9, 2457: 10, 2462: 11, 2467: 12,
+ 2472: 13}
+ if frequency not in ftoc:
+ logging.warning("The frequency %s can not be mapped to a channel, " \
+ "defaulting to channel 1.", frequency)
+ return 1
+ return ftoc[frequency]
+
+def is_sugar_adhoc_network(ssid):
+ """Checks whether an access point is a sugar Ad-hoc network.
+
+ Keyword arguments:
+ ssid -- Ssid of the access point.
+
+ Return: Boolean
+
+ """
+ return ssid.startswith('Ad-hoc Network')
+
+
+class WirelessSecurity(object):
+ def __init__(self):
+ self.key_mgmt = None
+ self.proto = None
+ self.group = None
+ self.pairwise = None
+
+ def get_dict(self):
+ wireless_security = {}
+ if self.key_mgmt is not None:
+ wireless_security['key-mgmt'] = self.key_mgmt
+ if self.proto is not None:
+ wireless_security['proto'] = self.proto
+ if self.pairwise is not None:
+ wireless_security['pairwise'] = self.pairwise
+ if self.group is not None:
+ wireless_security['group'] = self.group
+ return wireless_security
+
+class Wireless(object):
+ nm_name = "802-11-wireless"
+
+ def __init__(self):
+ self.ssid = None
+ self.security = None
+ self.mode = None
+ self.band = None
+ self.channel = None
+
+ def get_dict(self):
+ wireless = {'ssid': self.ssid}
+ if self.security:
+ wireless['security'] = self.security
+ if self.mode:
+ wireless['mode'] = self.mode
+ if self.band:
+ wireless['band'] = self.band
+ if self.channel:
+ wireless['channel'] = self.channel
+ return wireless
+
+
+class OlpcMesh(object):
+ nm_name = "802-11-olpc-mesh"
+
+ def __init__(self, channel, anycast_addr):
+ self.channel = channel
+ self.anycast_addr = anycast_addr
+
+ def get_dict(self):
+ ret = {
+ "ssid": dbus.ByteArray("olpc-mesh"),
+ "channel": self.channel,
+ }
+
+ if self.anycast_addr:
+ ret["dhcp-anycast-address"] = dbus.ByteArray(self.anycast_addr)
+ return ret
+
+
+class Connection(object):
+ def __init__(self):
+ self.id = None
+ self.uuid = None
+ self.type = None
+ self.autoconnect = False
+ self.timestamp = None
+
+ def get_dict(self):
+ connection = {'id': self.id,
+ 'uuid': self.uuid,
+ 'type': self.type,
+ 'autoconnect': self.autoconnect}
+ if self.timestamp:
+ connection['timestamp'] = self.timestamp
+ return connection
+
+class IP4Config(object):
+ def __init__(self):
+ self.method = None
+
+ def get_dict(self):
+ ip4_config = {}
+ if self.method is not None:
+ ip4_config['method'] = self.method
+ return ip4_config
+
+class Serial(object):
+ def __init__(self):
+ self.baud = None
+
+ def get_dict(self):
+ serial = {}
+
+ if self.baud is not None:
+ serial['baud'] = self.baud
+
+ return serial
+
+class Ppp(object):
+ def __init__(self):
+ pass
+
+ def get_dict(self):
+ ppp = {}
+ return ppp
+
+class Gsm(object):
+ def __init__(self):
+ self.apn = None
+ self.number = None
+ self.username = None
+
+ def get_dict(self):
+ gsm = {}
+
+ if self.apn is not None:
+ gsm['apn'] = self.apn
+ if self.number is not None:
+ gsm['number'] = self.number
+ if self.username is not None:
+ gsm['username'] = self.username
+
+ return gsm
+
+class Settings(object):
+ def __init__(self, wireless_cfg=None):
+ self.connection = Connection()
+ self.ip4_config = None
+ self.wireless_security = None
+
+ if wireless_cfg is not None:
+ self.wireless = wireless_cfg
+ else:
+ self.wireless = Wireless()
+
+ def get_dict(self):
+ settings = {}
+ settings['connection'] = self.connection.get_dict()
+ settings[self.wireless.nm_name] = self.wireless.get_dict()
+ if self.wireless_security is not None:
+ settings['802-11-wireless-security'] = \
+ self.wireless_security.get_dict()
+ if self.ip4_config is not None:
+ settings['ipv4'] = self.ip4_config.get_dict()
+ return settings
+
+class Secrets(object):
+ def __init__(self, settings):
+ self.settings = settings
+ self.wep_key = None
+ self.psk = None
+ self.auth_alg = None
+
+ def get_dict(self):
+ # Although we could just return the keys here, we instead return all
+ # of the network settings so that we can apply any late decisions made
+ # by the user (e.g. if they selected shared key authentication). see
+ # http://bugs.sugarlabs.org/ticket/1602
+ settings = self.settings.get_dict()
+ if '802-11-wireless-security' not in settings:
+ settings['802-11-wireless-security'] = {}
+
+ if self.wep_key is not None:
+ settings['802-11-wireless-security']['wep-key0'] = self.wep_key
+ if self.psk is not None:
+ settings['802-11-wireless-security']['psk'] = self.psk
+ if self.auth_alg is not None:
+ settings['802-11-wireless-security']['auth-alg'] = self.auth_alg
+
+ return settings
+
+class SettingsGsm(object):
+ def __init__(self):
+ self.connection = Connection()
+ self.ip4_config = IP4Config()
+ self.serial = Serial()
+ self.ppp = Ppp()
+ self.gsm = Gsm()
+
+ def get_dict(self):
+ settings = {}
+
+ settings['connection'] = self.connection.get_dict()
+ settings['serial'] = self.serial.get_dict()
+ settings['ppp'] = self.ppp.get_dict()
+ settings['gsm'] = self.gsm.get_dict()
+ settings['ipv4'] = self.ip4_config.get_dict()
+
+ return settings
+
+class SecretsGsm(object):
+ def __init__(self):
+ self.password = None
+ self.pin = None
+ self.puk = None
+
+ def get_dict(self):
+ secrets = {}
+ if self.password is not None:
+ secrets['password'] = self.password
+ if self.pin is not None:
+ secrets['pin'] = self.pin
+ if self.puk is not None:
+ secrets['puk'] = self.puk
+ return {'gsm': secrets}
+
+class NMSettings(dbus.service.Object):
+ def __init__(self):
+ bus = dbus.SystemBus()
+ bus_name = dbus.service.BusName(SETTINGS_SERVICE, bus=bus)
+ dbus.service.Object.__init__(self, bus_name, NM_SETTINGS_PATH)
+
+ self.connections = {}
+ self.secrets_request = dispatch.Signal()
+
+ @dbus.service.method(dbus_interface=NM_SETTINGS_IFACE,
+ in_signature='', out_signature='ao')
+ def ListConnections(self):
+ return self.connections.values()
+
+ @dbus.service.signal(NM_SETTINGS_IFACE, signature='o')
+ def NewConnection(self, connection_path):
+ pass
+
+ def add_connection(self, uuid, conn):
+ self.connections[uuid] = conn
+ conn.secrets_request.connect(self.__secrets_request_cb)
+ self.NewConnection(conn.path)
+
+ def __secrets_request_cb(self, sender, **kwargs):
+ self.secrets_request.send(self, connection=sender,
+ response=kwargs['response'])
+
+class SecretsResponse(object):
+ ''' Intermediate object to report the secrets from the dialog
+ back to the connection object and which will inform NM
+ '''
+ def __init__(self, connection, reply_cb, error_cb):
+ self._connection = connection
+ self._reply_cb = reply_cb
+ self._error_cb = error_cb
+
+ def set_secrets(self, secrets):
+ self._connection.set_secrets(secrets)
+ self._reply_cb(secrets.get_dict())
+
+ def set_error(self, error):
+ self._error_cb(error)
+
+class NMSettingsConnection(dbus.service.Object):
+ def __init__(self, path, settings, secrets):
+ bus = dbus.SystemBus()
+ bus_name = dbus.service.BusName(SETTINGS_SERVICE, bus=bus)
+ dbus.service.Object.__init__(self, bus_name, path)
+
+ self.path = path
+ self.secrets_request = dispatch.Signal()
+
+ self._settings = settings
+ self._secrets = secrets
+
+ def set_connected(self):
+ if self._settings.connection.type == NM_CONNECTION_TYPE_GSM:
+ self._settings.connection.timestamp = int(time.time())
+ else:
+ if not self._settings.connection.autoconnect:
+ self._settings.connection.autoconnect = True
+ self._settings.connection.timestamp = int(time.time())
+ if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
+ self.save()
+
+ def set_secrets(self, secrets):
+ self._secrets = secrets
+ if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
+ self.save()
+
+ def get_settings(self):
+ return self._settings
+
+ def save(self):
+ profile_path = env.get_profile_path()
+ config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
+
+ config = ConfigParser.ConfigParser()
+ try:
+ try:
+ if not config.read(config_path):
+ logging.error('Error reading the nm config file')
+ return
+ except ConfigParser.ParsingError:
+ logging.exception('Error reading the nm config file')
+ return
+ identifier = self._settings.connection.id
+
+ if identifier not in config.sections():
+ config.add_section(identifier)
+ config.set(identifier, 'type', self._settings.connection.type)
+ config.set(identifier, 'ssid', self._settings.wireless.ssid)
+ config.set(identifier, 'uuid', self._settings.connection.uuid)
+ config.set(identifier, 'autoconnect',
+ self._settings.connection.autoconnect)
+ if self._settings.connection.timestamp is not None:
+ config.set(identifier, 'timestamp',
+ self._settings.connection.timestamp)
+ if self._settings.wireless_security is not None:
+ if self._settings.wireless_security.key_mgmt is not None:
+ config.set(identifier, 'key-mgmt',
+ self._settings.wireless_security.key_mgmt)
+ if self._settings.wireless_security.proto is not None:
+ config.set(identifier, 'proto',
+ self._settings.wireless_security.proto)
+ if self._settings.wireless_security.pairwise is not None:
+ config.set(identifier, 'pairwise',
+ self._settings.wireless_security.pairwise)
+ if self._settings.wireless_security.group is not None:
+ config.set(identifier, 'group',
+ self._settings.wireless_security.group)
+ if self._settings.wireless.security is not None:
+ config.set(identifier, 'security',
+ self._settings.wireless.security)
+ if self._secrets is not None:
+ if self._settings.wireless_security.key_mgmt == 'none':
+ config.set(identifier, 'key', self._secrets.wep_key)
+ config.set(identifier, 'auth-alg', self._secrets.auth_alg)
+ elif self._settings.wireless_security.key_mgmt == 'wpa-psk':
+ config.set(identifier, 'key', self._secrets.psk)
+ except ConfigParser.Error, e:
+ logging.exception('Error constructing %s', identifier)
+ else:
+ f = open(config_path, 'w')
+ try:
+ config.write(f)
+ except ConfigParser.Error:
+ logging.exception('Can not write %s', config_path)
+ f.close()
+
+ @dbus.service.method(dbus_interface=NM_CONNECTION_IFACE,
+ in_signature='', out_signature='a{sa{sv}}')
+ def GetSettings(self):
+ return self._settings.get_dict()
+
+ @dbus.service.method(dbus_interface=NM_SECRETS_IFACE,
+ async_callbacks=('reply', 'error'),
+ in_signature='sasb', out_signature='a{sa{sv}}')
+ def GetSecrets(self, setting_name, hints, request_new, reply, error):
+ logging.debug('Secrets requested for connection %s request_new=%s',
+ self.path, request_new)
+ if request_new or self._secrets is None:
+ # request_new is for example the case when the pw on the AP changes
+ response = SecretsResponse(self, reply, error)
+ try:
+ self.secrets_request.send(self, response=response)
+ except Exception:
+ logging.exception('Error requesting the secrets via dialog')
+ else:
+ reply(self._secrets.get_dict())
+
+
+class AccessPoint(gobject.GObject):
+ __gsignals__ = {
+ 'props-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, device, model):
+ self.__gobject_init__()
+ self.device = device
+ self.model = model
+
+ self._initialized = False
+ self._bus = dbus.SystemBus()
+
+ self.name = ''
+ self.strength = 0
+ self.flags = 0
+ self.wpa_flags = 0
+ self.rsn_flags = 0
+ self.mode = 0
+ self.channel = 0
+
+ def initialize(self):
+ model_props = dbus.Interface(self.model,
+ 'org.freedesktop.DBus.Properties')
+ model_props.GetAll(NM_ACCESSPOINT_IFACE, byte_arrays=True,
+ reply_handler=self._ap_properties_changed_cb,
+ error_handler=self._get_all_props_error_cb)
+
+ self._bus.add_signal_receiver(self._ap_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self.model.object_path,
+ dbus_interface=NM_ACCESSPOINT_IFACE,
+ byte_arrays=True)
+
+ def network_hash(self):
+ """
+ This is a hash which uniquely identifies the network that this AP
+ is a bridge to. i.e. its expected for 2 APs with identical SSID and
+ other settings to have the same network hash, because we assume that
+ they are a part of the same underlying network.
+ """
+
+ # based on logic from nm-applet
+ fl = 0
+
+ if self.mode == NM_802_11_MODE_INFRA:
+ fl |= 1 << 0
+ elif self.mode == NM_802_11_MODE_ADHOC:
+ fl |= 1 << 1
+ else:
+ fl |= 1 << 2
+
+ # Separate out no encryption, WEP-only, and WPA-capable */
+ if (not (self.flags & NM_802_11_AP_FLAGS_PRIVACY)) \
+ and self.wpa_flags == NM_802_11_AP_SEC_NONE \
+ and self.rsn_flags == NM_802_11_AP_SEC_NONE:
+ fl |= 1 << 3
+ elif (self.flags & NM_802_11_AP_FLAGS_PRIVACY) \
+ and self.wpa_flags == NM_802_11_AP_SEC_NONE \
+ and self.rsn_flags == NM_802_11_AP_SEC_NONE:
+ fl |= 1 << 4
+ elif (not (self.flags & NM_802_11_AP_FLAGS_PRIVACY)) \
+ and self.wpa_flags != NM_802_11_AP_SEC_NONE \
+ and self.rsn_flags != NM_802_11_AP_SEC_NONE:
+ fl |= 1 << 5
+ else:
+ fl |= 1 << 6
+
+ hashstr = str(fl) + "@" + self.name
+ return hash(hashstr)
+
+ def _update_properties(self, properties):
+ if self._initialized:
+ old_hash = self.network_hash()
+ else:
+ old_hash = None
+
+ if 'Ssid' in properties:
+ self.name = properties['Ssid']
+ if 'Strength' in properties:
+ self.strength = properties['Strength']
+ if 'Flags' in properties:
+ self.flags = properties['Flags']
+ if 'WpaFlags' in properties:
+ self.wpa_flags = properties['WpaFlags']
+ if 'RsnFlags' in properties:
+ self.rsn_flags = properties['RsnFlags']
+ if 'Mode' in properties:
+ self.mode = properties['Mode']
+ if 'Frequency' in properties:
+ self.channel = frequency_to_channel(properties['Frequency'])
+
+ self._initialized = True
+ self.emit('props-changed', old_hash)
+
+ def _get_all_props_error_cb(self, err):
+ logging.error('Error getting the access point properties: %s', err)
+
+ def _ap_properties_changed_cb(self, properties):
+ self._update_properties(properties)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self._ap_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self.model.object_path,
+ dbus_interface=NM_ACCESSPOINT_IFACE)
+
+def get_settings():
+ global _nm_settings
+ if _nm_settings is None:
+ try:
+ _nm_settings = NMSettings()
+ except dbus.DBusException:
+ logging.exception('Cannot create the UserSettings service.')
+ load_connections()
+ return _nm_settings
+
+def find_connection_by_ssid(ssid):
+ connections = get_settings().connections
+
+ for conn_index in connections:
+ connection = connections[conn_index]
+ if connection._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
+ if connection._settings.wireless.ssid == ssid:
+ return connection
+
+ return None
+
+def add_connection(uuid, settings, secrets=None):
+ global _conn_counter
+
+ path = NM_SETTINGS_PATH + '/' + str(_conn_counter)
+ _conn_counter += 1
+
+ conn = NMSettingsConnection(path, settings, secrets)
+ _nm_settings.add_connection(uuid, conn)
+ return conn
+
+def load_wifi_connections():
+ profile_path = env.get_profile_path()
+ config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
+
+ config = ConfigParser.ConfigParser()
+
+ if not os.path.exists(config_path):
+ if not os.path.exists(os.path.dirname(config_path)):
+ os.makedirs(os.path.dirname(config_path), 0755)
+ f = open(config_path, 'w')
+ config.write(f)
+ f.close()
+
+ try:
+ if not config.read(config_path):
+ logging.error('Error reading the nm config file')
+ return
+ except ConfigParser.ParsingError:
+ logging.exception('Error reading the nm config file')
+ return
+
+ for section in config.sections():
+ try:
+ settings = Settings()
+ settings.connection.id = section
+ ssid = config.get(section, 'ssid')
+ settings.wireless.ssid = dbus.ByteArray(ssid)
+ uuid = config.get(section, 'uuid')
+ settings.connection.uuid = uuid
+ nmtype = config.get(section, 'type')
+ settings.connection.type = nmtype
+ autoconnect = bool(config.get(section, 'autoconnect'))
+ settings.connection.autoconnect = autoconnect
+
+ if config.has_option(section, 'timestamp'):
+ timestamp = int(config.get(section, 'timestamp'))
+ settings.connection.timestamp = timestamp
+
+ secrets = None
+ if config.has_option(section, 'key-mgmt'):
+ secrets = Secrets(settings)
+ settings.wireless_security = WirelessSecurity()
+ mgmt = config.get(section, 'key-mgmt')
+ settings.wireless_security.key_mgmt = mgmt
+ security = config.get(section, 'security')
+ settings.wireless.security = security
+ key = config.get(section, 'key')
+ if mgmt == 'none':
+ secrets.wep_key = key
+ auth_alg = config.get(section, 'auth-alg')
+ secrets.auth_alg = auth_alg
+ elif mgmt == 'wpa-psk':
+ secrets.psk = key
+ if config.has_option(section, 'proto'):
+ value = config.get(section, 'proto')
+ settings.wireless_security.proto = value
+ if config.has_option(section, 'group'):
+ value = config.get(section, 'group')
+ settings.wireless_security.group = value
+ if config.has_option(section, 'pairwise'):
+ value = config.get(section, 'pairwise')
+ settings.wireless_security.pairwise = value
+ except ConfigParser.Error:
+ logging.exception('Error reading section')
+ else:
+ add_connection(uuid, settings, secrets)
+
+
+def load_gsm_connection():
+ _BAUD_RATE = 115200
+
+ client = gconf.client_get_default()
+
+ username = client.get_string(GSM_USERNAME_PATH) or ''
+ password = client.get_string(GSM_PASSWORD_PATH) or ''
+ number = client.get_string(GSM_NUMBER_PATH) or ''
+ apn = client.get_string(GSM_APN_PATH) or ''
+ pin = client.get_string(GSM_PIN_PATH) or ''
+ puk = client.get_string(GSM_PUK_PATH) or ''
+
+ if username and number and apn:
+ settings = SettingsGsm()
+ settings.gsm.username = username
+ settings.gsm.number = number
+ settings.gsm.apn = apn
+
+ secrets = SecretsGsm()
+ secrets.pin = pin
+ secrets.puk = puk
+ secrets.password = password
+
+ settings.connection.id = 'gsm'
+ settings.connection.type = NM_CONNECTION_TYPE_GSM
+ uuid = settings.connection.uuid = unique_id()
+ settings.connection.autoconnect = False
+ settings.ip4_config.method = 'auto'
+ settings.serial.baud = _BAUD_RATE
+
+ try:
+ add_connection(uuid, settings, secrets)
+ except Exception:
+ logging.exception('Error adding gsm connection to NMSettings.')
+ else:
+ logging.exception("No gsm connection was set in GConf.")
+
+def load_connections():
+ load_wifi_connections()
+ load_gsm_connection()
+
+def find_gsm_connection():
+ connections = get_settings().connections
+
+ for connection in connections.values():
+ if connection.get_settings().connection.type == NM_CONNECTION_TYPE_GSM:
+ return connection
+
+ logging.debug('There is no gsm connection in the NMSettings.')
+ return None
diff --git a/shell/src/jarabe/model/notifications.py b/shell/src/jarabe/model/notifications.py
new file mode 100644
index 0000000..f2e2d65
--- /dev/null
+++ b/shell/src/jarabe/model/notifications.py
@@ -0,0 +1,95 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import logging
+
+import dbus
+
+from sugar import dispatch
+
+from jarabe import config
+
+_DBUS_SERVICE = "org.freedesktop.Notifications"
+_DBUS_IFACE = "org.freedesktop.Notifications"
+_DBUS_PATH = "/org/freedesktop/Notifications"
+
+class NotificationService(dbus.service.Object):
+ def __init__(self):
+ bus = dbus.SessionBus()
+ bus_name = dbus.service.BusName(_DBUS_SERVICE, bus=bus)
+ dbus.service.Object.__init__(self, bus_name, _DBUS_PATH)
+
+ self._notification_counter = 0
+ self.notification_received = dispatch.Signal()
+ self.notification_cancelled = dispatch.Signal()
+
+ @dbus.service.method(_DBUS_IFACE,
+ in_signature='susssava{sv}i', out_signature='u')
+ def Notify(self, app_name, replaces_id, app_icon, summary, body, actions,
+ hints, expire_timeout):
+
+ logging.debug('Received notification: %r', [app_name, replaces_id,
+ '<app_icon>', summary, body, actions, '<hints>', expire_timeout])
+
+ if replaces_id > 0:
+ notification_id = replaces_id
+ else:
+ if self._notification_counter == sys.maxint:
+ self._notification_counter = 1
+ else:
+ self._notification_counter += 1
+ notification_id = self._notification_counter
+
+ self.notification_received.send(self, app_name=app_name,
+ replaces_id=replaces_id, app_icon=app_icon, summary=summary,
+ body=body, actions=actions, hints=hints,
+ expire_timeout=expire_timeout)
+
+ return notification_id
+
+ @dbus.service.method(_DBUS_IFACE, in_signature='u', out_signature='')
+ def CloseNotification(self, notification_id):
+ self.notification_cancelled.send(self, notification_id=notification_id)
+
+ @dbus.service.method(_DBUS_IFACE, in_signature='', out_signature='as')
+ def GetCapabilities(self):
+ return []
+
+ @dbus.service.method(_DBUS_IFACE, in_signature='', out_signature='sss')
+ def GetServerInformation(self, name, vendor, version):
+ return 'Sugar Shell', 'Sugar', config.version
+
+
+ @dbus.service.signal(_DBUS_IFACE, signature="uu")
+ def NotificationClosed(self, notification_id, reason):
+ pass
+
+ @dbus.service.signal(_DBUS_IFACE, signature="us")
+ def ActionInvoked(self, notification_id, action_key):
+ pass
+
+_instance = None
+
+def get_service():
+ global _instance
+ if not _instance:
+ _instance = NotificationService()
+ return _instance
+
+def init():
+ get_service()
+
diff --git a/shell/src/jarabe/model/olpcmesh.py b/shell/src/jarabe/model/olpcmesh.py
new file mode 100644
index 0000000..60f6be4
--- /dev/null
+++ b/shell/src/jarabe/model/olpcmesh.py
@@ -0,0 +1,214 @@
+# Copyright (C) 2009, 2010 One Laptop per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import dbus
+import gobject
+
+from jarabe.model import network
+from jarabe.model.network import Settings
+from jarabe.model.network import OlpcMesh as OlpcMeshSettings
+from sugar.util import unique_id
+
+_NM_SERVICE = 'org.freedesktop.NetworkManager'
+_NM_IFACE = 'org.freedesktop.NetworkManager'
+_NM_PATH = '/org/freedesktop/NetworkManager'
+_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
+_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
+
+_XS_ANYCAST = "\xc0\x27\xc0\x27\xc0\x00"
+
+DEVICE_STATE_UNKNOWN = 0
+DEVICE_STATE_UNMANAGED = 1
+DEVICE_STATE_UNAVAILABLE = 2
+DEVICE_STATE_DISCONNECTED = 3
+DEVICE_STATE_PREPARE = 4
+DEVICE_STATE_CONFIG = 5
+DEVICE_STATE_NEED_AUTH = 6
+DEVICE_STATE_IP_CONFIG = 7
+DEVICE_STATE_ACTIVATED = 8
+DEVICE_STATE_FAILED = 9
+
+class OlpcMeshManager(object):
+ def __init__(self, mesh_device):
+ self._bus = dbus.SystemBus()
+
+ self.mesh_device = mesh_device
+ self.eth_device = self._get_companion_device()
+
+ self._connection_queue = []
+ """Stack of connections that we'll iterate through until we find one
+ that works.
+
+ """
+
+ props = dbus.Interface(self.mesh_device,
+ 'org.freedesktop.DBus.Properties')
+ props.Get(_NM_DEVICE_IFACE, 'State',
+ reply_handler=self.__get_mesh_state_reply_cb,
+ error_handler=self.__get_state_error_cb)
+
+ props = dbus.Interface(self.eth_device,
+ 'org.freedesktop.DBus.Properties')
+ props.Get(_NM_DEVICE_IFACE, 'State',
+ reply_handler=self.__get_eth_state_reply_cb,
+ error_handler=self.__get_state_error_cb)
+
+ self._bus.add_signal_receiver(self.__eth_device_state_changed_cb,
+ signal_name='StateChanged',
+ path=self.eth_device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ self._bus.add_signal_receiver(self.__mshdev_state_changed_cb,
+ signal_name='StateChanged',
+ path=self.mesh_device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ self._idle_source = 0
+ self._mesh_device_state = DEVICE_STATE_UNKNOWN
+ self._eth_device_state = DEVICE_STATE_UNKNOWN
+
+ if self._have_configured_connections():
+ self._start_automesh_timer()
+ else:
+ self._start_automesh()
+
+ def _get_companion_device(self):
+ props = dbus.Interface(self.mesh_device,
+ 'org.freedesktop.DBus.Properties')
+ eth_device_o = props.Get(_NM_OLPC_MESH_IFACE, 'Companion')
+ return self._bus.get_object(_NM_SERVICE, eth_device_o)
+
+ def _have_configured_connections(self):
+ return len(network.get_settings().connections) > 0
+
+ def _start_automesh_timer(self):
+ """Start our timer system which basically looks for 10 seconds of
+ inactivity on both devices, then starts automesh.
+
+ """
+ if self._idle_source != 0:
+ gobject.source_remove(self._idle_source)
+ self._idle_source = gobject.timeout_add_seconds(10, self._idle_check)
+
+ def __get_state_error_cb(self, err):
+ logging.debug('Error getting the device state: %s', err)
+
+ def __get_mesh_state_reply_cb(self, state):
+ self._mesh_device_state = state
+ self._maybe_schedule_idle_check()
+
+ def __get_eth_state_reply_cb(self, state):
+ self._eth_device_state = state
+ self._maybe_schedule_idle_check()
+
+ def __eth_device_state_changed_cb(self, new_state, old_state, reason):
+ """If a connection is activated on the eth device, stop trying our
+ automatic connections.
+
+ """
+ self._eth_device_state = new_state
+ self._maybe_schedule_idle_check()
+
+ if new_state >= DEVICE_STATE_PREPARE \
+ and new_state <= DEVICE_STATE_ACTIVATED \
+ and len(self._connection_queue) > 0:
+ self._connection_queue = []
+
+ def __mshdev_state_changed_cb(self, new_state, old_state, reason):
+ self._mesh_device_state = new_state
+ self._maybe_schedule_idle_check()
+
+ if new_state == DEVICE_STATE_FAILED:
+ self._try_next_connection_from_queue()
+ elif new_state == DEVICE_STATE_ACTIVATED \
+ and len(self._connection_queue) > 0:
+ self._empty_connection_queue()
+
+ def _maybe_schedule_idle_check(self):
+ if self._mesh_device_state == DEVICE_STATE_DISCONNECTED \
+ and self._eth_device_state == DEVICE_STATE_DISCONNECTED:
+ self._start_automesh_timer()
+
+ def _idle_check(self):
+ if self._mesh_device_state == DEVICE_STATE_DISCONNECTED \
+ and self._eth_device_state == DEVICE_STATE_DISCONNECTED:
+ logging.debug("starting automesh due to inactivity")
+ self._start_automesh()
+ return False
+
+ def _make_connection(self, channel, anycast_address=None):
+ wireless_config = OlpcMeshSettings(channel, anycast_address)
+ settings = Settings(wireless_cfg=wireless_config)
+ if not anycast_address:
+ settings.ip4_config = network.IP4Config()
+ settings.ip4_config.method = 'link-local'
+ settings.connection.id = 'olpc-mesh-' + str(channel)
+ settings.connection.uuid = unique_id()
+ settings.connection.type = '802-11-olpc-mesh'
+ connection = network.add_connection(settings.connection.id, settings)
+ return connection
+
+ def __activate_reply_cb(self, connection):
+ logging.debug('Connection activated: %s', connection)
+
+ def __activate_error_cb(self, err):
+ logging.error('Failed to activate connection: %s', err)
+
+ def _activate_connection(self, channel, anycast_address=None):
+ logging.debug("activate channel %d anycast %r",
+ channel, anycast_address)
+ proxy = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ network_manager = dbus.Interface(proxy, _NM_IFACE)
+ connection = self._make_connection(channel, anycast_address)
+
+ network_manager.ActivateConnection(network.SETTINGS_SERVICE,
+ connection.path,
+ self.mesh_device.object_path,
+ self.mesh_device.object_path,
+ reply_handler=self.__activate_reply_cb,
+ error_handler=self.__activate_error_cb)
+
+ def _try_next_connection_from_queue(self):
+ if len(self._connection_queue) == 0:
+ return
+
+ channel, anycast = self._connection_queue.pop()
+ self._activate_connection(channel, anycast)
+
+ def _empty_connection_queue(self):
+ self._connection_queue = []
+
+ def user_activate_channel(self, channel):
+ """Activate a mesh connection on a user-specified channel.
+ Looks for XS first, then resorts to simple mesh."""
+ self._empty_connection_queue()
+ self._connection_queue.append((channel, None))
+ self._connection_queue.append((channel, _XS_ANYCAST))
+ self._try_next_connection_from_queue()
+
+ def _start_automesh(self):
+ """Start meshing automatically, intended when there are no better
+ networks to connect to. First looks for XS on all channels, then falls
+ back to simple mesh on channel 1."""
+ self._empty_connection_queue()
+ self._connection_queue.append((1, None))
+ self._connection_queue.append((11, _XS_ANYCAST))
+ self._connection_queue.append((6, _XS_ANYCAST))
+ self._connection_queue.append((1, _XS_ANYCAST))
+ self._try_next_connection_from_queue()
+
diff --git a/shell/src/jarabe/model/screen.py b/shell/src/jarabe/model/screen.py
new file mode 100644
index 0000000..4403c1c
--- /dev/null
+++ b/shell/src/jarabe/model/screen.py
@@ -0,0 +1,43 @@
+# Copyright (C) 2006-2008 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import dbus
+
+_HARDWARE_MANAGER_INTERFACE = 'org.freedesktop.ohm.Keystore'
+_HARDWARE_MANAGER_SERVICE = 'org.freedesktop.ohm'
+_HARDWARE_MANAGER_OBJECT_PATH = '/org/freedesktop/ohm/Keystore'
+
+_ohm_service = None
+
+def _get_ohm():
+ global _ohm_service
+ if _ohm_service is None:
+ bus = dbus.SystemBus()
+ proxy = bus.get_object(_HARDWARE_MANAGER_SERVICE,
+ _HARDWARE_MANAGER_OBJECT_PATH,
+ follow_name_owner_changes=True)
+ _ohm_service = dbus.Interface(proxy, _HARDWARE_MANAGER_INTERFACE)
+
+ return _ohm_service
+
+def set_dcon_freeze(frozen):
+ try:
+ _get_ohm().SetKey("display.dcon_freeze", frozen)
+ except dbus.DBusException:
+ logging.error('Cannot unfreeze the DCON')
+
diff --git a/shell/src/jarabe/model/session.py b/shell/src/jarabe/model/session.py
new file mode 100644
index 0000000..9e0f087
--- /dev/null
+++ b/shell/src/jarabe/model/session.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2008, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import dbus
+import os
+import signal
+import sys
+import logging
+
+from sugar import session
+from sugar import env
+
+_session_manager = None
+
+class SessionManager(session.SessionManager):
+ MODE_LOGOUT = 0
+ MODE_SHUTDOWN = 1
+ MODE_REBOOT = 2
+
+ def __init__(self):
+ session.SessionManager.__init__(self)
+ self._logout_mode = None
+
+ def logout(self):
+ self._logout_mode = self.MODE_LOGOUT
+ self.initiate_shutdown()
+
+ def shutdown(self):
+ self._logout_mode = self.MODE_SHUTDOWN
+ self.initiate_shutdown()
+
+ def reboot(self):
+ self._logout_mode = self.MODE_REBOOT
+ self.initiate_shutdown()
+
+ def shutdown_completed(self):
+ if env.is_emulator():
+ self._close_emulator()
+ elif self._logout_mode != self.MODE_LOGOUT:
+ try:
+ bus = dbus.SystemBus()
+ proxy = bus.get_object('org.freedesktop.Hal',
+ '/org/freedesktop/Hal/devices/computer')
+ pm = dbus.Interface(proxy,
+ 'org.freedesktop.Hal.Device.SystemPowerManagement')
+
+ if self._logout_mode == self.MODE_SHUTDOWN:
+ pm.Shutdown()
+ elif self._logout_mode == self.MODE_REBOOT:
+ pm.Reboot()
+ except:
+ logging.exception('Can not stop sugar')
+ self.session.cancel_shutdown()
+ return
+
+ session.SessionManager.shutdown_completed(self)
+ gtk.main_quit()
+
+ def _close_emulator(self):
+ gtk.main_quit()
+
+ if os.environ.has_key('SUGAR_EMULATOR_PID'):
+ pid = int(os.environ['SUGAR_EMULATOR_PID'])
+ os.kill(pid, signal.SIGTERM)
+
+ # Need to call this ASAP so the atexit handlers get called before we get
+ # killed by the X (dis)connection
+ sys.exit()
+
+def get_session_manager():
+ global _session_manager
+
+ if _session_manager == None:
+ _session_manager = SessionManager()
+ return _session_manager
diff --git a/shell/src/jarabe/model/shell.py b/shell/src/jarabe/model/shell.py
new file mode 100644
index 0000000..db0e050
--- /dev/null
+++ b/shell/src/jarabe/model/shell.py
@@ -0,0 +1,641 @@
+# Copyright (C) 2006-2007 Owen Williams.
+# Copyright (C) 2006-2008 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+import time
+
+import gconf
+import wnck
+import gobject
+import gtk
+import dbus
+
+from sugar import wm
+from sugar import dispatch
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.model.bundleregistry import get_registry
+from jarabe.model import neighborhood
+
+_SERVICE_NAME = "org.laptop.Activity"
+_SERVICE_PATH = "/org/laptop/Activity"
+_SERVICE_INTERFACE = "org.laptop.Activity"
+
+
+class Activity(gobject.GObject):
+ """Activity which appears in the "Home View" of the Sugar shell
+
+ This class stores the Sugar Shell's metadata regarding a
+ given activity/application in the system. It interacts with
+ the sugar.activity.* modules extensively in order to
+ accomplish its tasks.
+ """
+
+ __gtype_name__ = 'SugarHomeActivity'
+
+ LAUNCHING = 0
+ LAUNCH_FAILED = 1
+ LAUNCHED = 2
+
+ def __init__(self, activity_info, activity_id, window=None):
+ """Initialise the HomeActivity
+
+ activity_info -- sugar.activity.registry.ActivityInfo instance,
+ provides the information required to actually
+ create the new instance. This is, in effect,
+ the "type" of activity being created.
+ activity_id -- unique identifier for this instance
+ of the activity type
+ window -- Main WnckWindow of the activity
+ """
+ gobject.GObject.__init__(self)
+
+ self._window = None
+ self._service = None
+ self._activity_id = activity_id
+ self._activity_info = activity_info
+ self._launch_time = time.time()
+ self._launch_status = Activity.LAUNCHING
+
+ if window is not None:
+ self.set_window(window)
+
+ self._retrieve_service()
+
+ self._name_owner_changed_handler = None
+ if not self._service:
+ bus = dbus.SessionBus()
+ self._name_owner_changed_handler = bus.add_signal_receiver(
+ self._name_owner_changed_cb,
+ signal_name="NameOwnerChanged",
+ dbus_interface="org.freedesktop.DBus")
+
+ self._launch_completed_hid = get_model().connect('launch-completed',
+ self.__launch_completed_cb)
+ self._launch_failed_hid = get_model().connect('launch-failed',
+ self.__launch_failed_cb)
+
+ def get_launch_status(self):
+ return self._launch_status
+
+ launch_status = gobject.property(getter=get_launch_status)
+
+ def set_window(self, window):
+ """Set the window for the activity
+
+ We allow resetting the window for an activity so that we
+ can replace the launcher once we get its real window.
+ """
+ if not window:
+ raise ValueError("window must be valid")
+ self._window = window
+
+ def get_service(self):
+ """Get the activity service
+
+ Note that non-native Sugar applications will not have
+ such a service, so the return value will be None in
+ those cases.
+ """
+
+ return self._service
+
+ def get_title(self):
+ """Retrieve the application's root window's suggested title"""
+ if self._window:
+ return self._window.get_name()
+ else:
+ return ''
+
+ def get_icon_path(self):
+ """Retrieve the activity's icon (file) name"""
+ if self.is_journal():
+ icon_theme = gtk.icon_theme_get_default()
+ info = icon_theme.lookup_icon('activity-journal',
+ gtk.ICON_SIZE_SMALL_TOOLBAR, 0)
+ if not info:
+ return None
+ fname = info.get_filename()
+ del info
+ return fname
+ elif self._activity_info:
+ return self._activity_info.get_icon()
+ else:
+ return None
+
+ def get_icon_color(self):
+ """Retrieve the appropriate icon colour for this activity
+
+ Uses activity_id to index into the PresenceService's
+ set of activity colours, if the PresenceService does not
+ have an entry (implying that this is not a Sugar-shared application)
+ uses the local user's profile colour for the icon.
+ """
+ # HACK to suppress warning in logs when activity isn't found
+ # (if it's locally launched and not shared yet)
+ activity = None
+ for act in neighborhood.get_model().get_activities():
+ if self._activity_id == act.activity_id:
+ activity = act
+ break
+
+ if activity != None:
+ return activity.props.color
+ else:
+ client = gconf.client_get_default()
+ return XoColor(client.get_string("/desktop/sugar/user/color"))
+
+ def get_activity_id(self):
+ """Retrieve the "activity_id" passed in to our constructor
+
+ This is a "globally likely unique" identifier generated by
+ sugar.util.unique_id
+ """
+ return self._activity_id
+
+ def get_xid(self):
+ """Retrieve the X-windows ID of our root window"""
+ if self._window is not None:
+ return self._window.get_xid()
+ else:
+ return None
+
+ def get_window(self):
+ """Retrieve the X-windows root window of this application
+
+ This was stored by the set_window method, which was
+ called by HomeModel._add_activity, which was called
+ via a callback that looks for all 'window-opened'
+ events.
+
+ HomeModel currently uses a dbus service query on the
+ activity to determine to which HomeActivity the newly
+ launched window belongs.
+ """
+ return self._window
+
+ def get_type(self):
+ """Retrieve the activity bundle id for future reference"""
+ if self._window is None:
+ return None
+ else:
+ return wm.get_bundle_id(self._window)
+
+ def is_journal(self):
+ """Returns boolean if the activity is of type JournalActivity"""
+ return self.get_type() == 'org.laptop.JournalActivity'
+
+ def get_launch_time(self):
+ """Return the time at which the activity was first launched
+
+ Format is floating-point time.time() value
+ (seconds since the epoch)
+ """
+ return self._launch_time
+
+ def get_pid(self):
+ """Returns the activity's PID"""
+ return self._window.get_pid()
+
+ def get_bundle_path(self):
+ """Returns the activity's bundle directory"""
+ if self._activity_info is None:
+ return None
+ else:
+ return self._activity_info.get_path()
+
+ def get_activity_name(self):
+ """Returns the activity's bundle name"""
+ if self._activity_info is None:
+ return None
+ else:
+ return self._activity_info.get_name()
+
+ def equals(self, activity):
+ if self._activity_id and activity.get_activity_id():
+ return self._activity_id == activity.get_activity_id()
+ if self._window.get_xid() and activity.get_xid():
+ return self._window.get_xid() == activity.get_xid()
+ return False
+
+ def _get_service_name(self):
+ if self._activity_id:
+ return _SERVICE_NAME + self._activity_id
+ else:
+ return None
+
+ def _retrieve_service(self):
+ if not self._activity_id:
+ return
+
+ try:
+ bus = dbus.SessionBus()
+ proxy = bus.get_object(self._get_service_name(),
+ _SERVICE_PATH + "/" + self._activity_id)
+ self._service = dbus.Interface(proxy, _SERVICE_INTERFACE)
+ except dbus.DBusException:
+ self._service = None
+
+ def _name_owner_changed_cb(self, name, old, new):
+ if name == self._get_service_name():
+ if old and not new:
+ logging.debug('Activity._name_owner_changed_cb: ' \
+ 'activity %s went away', name)
+ self._name_owner_changed_handler.remove()
+ self._name_owner_changed_handler = None
+ self._service = None
+ elif not old and new:
+ logging.debug('Activity._name_owner_changed_cb: ' \
+ 'activity %s started up', name)
+ self._retrieve_service()
+ self.set_active(True)
+
+ def set_active(self, state):
+ """Propagate the current state to the activity object"""
+ if self._service is not None:
+ self._service.SetActive(state,
+ reply_handler=self._set_active_success,
+ error_handler=self._set_active_error)
+
+ def _set_active_success(self):
+ pass
+
+ def _set_active_error(self, err):
+ logging.error("set_active() failed: %s", err)
+
+ def _set_launch_status(self, value):
+ get_model().disconnect(self._launch_completed_hid)
+ get_model().disconnect(self._launch_failed_hid)
+ self._launch_completed_hid = None
+ self._launch_failed_hid = None
+ self._launch_status = value
+ self.notify('launch_status')
+
+ def __launch_completed_cb(self, model, home_activity):
+ if home_activity is self:
+ self._set_launch_status(Activity.LAUNCHED)
+
+ def __launch_failed_cb(self, model, home_activity):
+ if home_activity is self:
+ self._set_launch_status(Activity.LAUNCH_FAILED)
+
+
+class ShellModel(gobject.GObject):
+ """Model of the shell (activity management)
+
+ The ShellModel is basically the point of registration
+ for all running activities within Sugar. It traps
+ events that tell the system there is a new activity
+ being created (generated by the activity factories),
+ or removed, as well as those which tell us that the
+ currently focussed activity has changed.
+
+ The HomeModel tracks a set of HomeActivity instances,
+ which are tracking the window to activity mappings
+ the activity factories have set up.
+ """
+
+ __gsignals__ = {
+ 'activity-added': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'activity-removed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'active-activity-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'tabbing-activity-changed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'launch-started': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'launch-completed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'launch-failed': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ ZOOM_MESH = 0
+ ZOOM_GROUP = 1
+ ZOOM_HOME = 2
+ ZOOM_ACTIVITY = 3
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._screen = wnck.screen_get_default()
+ self._screen.connect('window-opened', self._window_opened_cb)
+ self._screen.connect('window-closed', self._window_closed_cb)
+ self._screen.connect('active-window-changed',
+ self._active_window_changed_cb)
+
+ self.zoom_level_changed = dispatch.Signal()
+
+ self._desktop_level = self.ZOOM_HOME
+ self._zoom_level = self.ZOOM_HOME
+ self._current_activity = None
+ self._activities = []
+ self._active_activity = None
+ self._tabbing_activity = None
+ self._launchers = {}
+
+ self._screen.toggle_showing_desktop(True)
+
+ def get_launcher(self, activity_id):
+ return self._launchers.get(str(activity_id))
+
+ def register_launcher(self, activity_id, launcher):
+ self._launchers[activity_id] = launcher
+
+ def unregister_launcher(self, activity_id):
+ if activity_id in self._launchers:
+ del self._launchers[activity_id]
+
+ def _update_zoom_level(self, window):
+ if window.get_window_type() == wnck.WINDOW_DIALOG:
+ return
+ elif window.get_window_type() == wnck.WINDOW_NORMAL:
+ new_level = self.ZOOM_ACTIVITY
+ else:
+ new_level = self._desktop_level
+
+ if self._zoom_level != new_level:
+ old_level = self._zoom_level
+ self._zoom_level = new_level
+ self.zoom_level_changed.send(self, old_level=old_level,
+ new_level=new_level)
+
+ def set_zoom_level(self, new_level, x_event_time=0):
+ old_level = self.zoom_level
+ if old_level == new_level:
+ return
+
+ if old_level != self.ZOOM_ACTIVITY:
+ screen = gtk.gdk.screen_get_default()
+ active_window_type = screen.get_active_window().get_type_hint()
+ if active_window_type != gtk.gdk.WINDOW_TYPE_HINT_DESKTOP:
+ return
+
+ self._zoom_level = new_level
+ if new_level is not self.ZOOM_ACTIVITY:
+ self._desktop_level = new_level
+
+ self.zoom_level_changed.send(self, old_level=old_level,
+ new_level=new_level)
+
+ show_desktop = new_level is not self.ZOOM_ACTIVITY
+ self._screen.toggle_showing_desktop(show_desktop)
+
+ if new_level is self.ZOOM_ACTIVITY:
+ # activate the window, in case it was iconified
+ # (e.g. during sugar launch, the Journal starts in this state)
+ window = self._active_activity.get_window()
+ if window:
+ window.activate(x_event_time or gtk.get_current_event_time())
+
+ def _get_zoom_level(self):
+ return self._zoom_level
+
+ zoom_level = property(_get_zoom_level)
+
+ def _get_activities_with_window(self):
+ ret = []
+ for i in self._activities:
+ if i.get_window() is not None:
+ ret.append(i)
+ return ret
+
+ def get_previous_activity(self, current=None):
+ if not current:
+ current = self._active_activity
+
+ activities = self._get_activities_with_window()
+ i = activities.index(current)
+ if len(activities) == 0:
+ return None
+ elif i - 1 >= 0:
+ return activities[i - 1]
+ else:
+ return activities[len(activities) - 1]
+
+ def get_next_activity(self, current=None):
+ if not current:
+ current = self._active_activity
+
+ activities = self._get_activities_with_window()
+ i = activities.index(current)
+ if len(activities) == 0:
+ return None
+ elif i + 1 < len(activities):
+ return activities[i + 1]
+ else:
+ return activities[0]
+
+ def get_active_activity(self):
+ """Returns the activity that the user is currently working in"""
+ return self._active_activity
+
+ def get_tabbing_activity(self):
+ """Returns the activity that is currently highlighted during tabbing"""
+ return self._tabbing_activity
+
+ def set_tabbing_activity(self, activity):
+ """Sets the activity that is currently highlighted during tabbing"""
+ self._tabbing_activity = activity
+ self.emit("tabbing-activity-changed", self._tabbing_activity)
+
+ def _set_active_activity(self, home_activity):
+ if self._active_activity == home_activity:
+ return
+
+ if home_activity:
+ home_activity.set_active(True)
+
+ if self._active_activity:
+ self._active_activity.set_active(False)
+
+ self._active_activity = home_activity
+ self.emit('active-activity-changed', self._active_activity)
+
+ def __iter__(self):
+ return iter(self._activities)
+
+ def __len__(self):
+ return len(self._activities)
+
+ def __getitem__(self, i):
+ return self._activities[i]
+
+ def index(self, obj):
+ return self._activities.index(obj)
+
+ def _window_opened_cb(self, screen, window):
+ if window.get_window_type() == wnck.WINDOW_NORMAL:
+ home_activity = None
+
+ activity_id = wm.get_activity_id(window)
+
+ service_name = wm.get_bundle_id(window)
+ if service_name:
+ registry = get_registry()
+ activity_info = registry.get_bundle(service_name)
+ else:
+ activity_info = None
+
+ if activity_id:
+ home_activity = self.get_activity_by_id(activity_id)
+
+ xid = window.get_xid()
+ gdk_window = gtk.gdk.window_foreign_new(xid)
+ gdk_window.set_decorations(0)
+
+ window.maximize()
+
+ if not home_activity:
+ home_activity = Activity(activity_info, activity_id, window)
+ self._add_activity(home_activity)
+ else:
+ home_activity.set_window(window)
+
+ if wm.get_sugar_window_type(window) != 'launcher':
+ self.emit('launch-completed', home_activity)
+
+ startup_time = time.time() - home_activity.get_launch_time()
+ logging.debug('%s launched in %f seconds.',
+ home_activity.get_type(), startup_time)
+
+ if self._active_activity is None:
+ self._set_active_activity(home_activity)
+
+ def _window_closed_cb(self, screen, window):
+ if window.get_window_type() == wnck.WINDOW_NORMAL:
+ if self._get_activity_by_xid(window.get_xid()) is not None:
+ self._remove_activity_by_xid(window.get_xid())
+
+ def _get_activity_by_xid(self, xid):
+ for home_activity in self._activities:
+ if home_activity.get_xid() == xid:
+ return home_activity
+ return None
+
+ def get_activity_by_id(self, activity_id):
+ for home_activity in self._activities:
+ if home_activity.get_activity_id() == activity_id:
+ return home_activity
+ return None
+
+ def _active_window_changed_cb(self, screen, previous_window=None):
+ window = screen.get_active_window()
+ if window is None:
+ return
+
+ if window.get_window_type() != wnck.WINDOW_DIALOG:
+ while window.get_transient() is not None:
+ window = window.get_transient()
+
+ act = self._get_activity_by_xid(window.get_xid())
+ if act is not None:
+ self._set_active_activity(act)
+
+ self._update_zoom_level(window)
+
+ def _add_activity(self, home_activity):
+ self._activities.append(home_activity)
+ self.emit('activity-added', home_activity)
+
+ def _remove_activity(self, home_activity):
+ if home_activity == self._active_activity:
+ windows = wnck.screen_get_default().get_windows_stacked()
+ windows.reverse()
+ for window in windows:
+ new_activity = self._get_activity_by_xid(window.get_xid())
+ if new_activity is not None:
+ self._set_active_activity(new_activity)
+ break
+ else:
+ logging.error('No activities are running')
+ self._set_active_activity(None)
+
+ self.emit('activity-removed', home_activity)
+ self._activities.remove(home_activity)
+
+ def _remove_activity_by_xid(self, xid):
+ home_activity = self._get_activity_by_xid(xid)
+ if home_activity:
+ self._remove_activity(home_activity)
+ else:
+ logging.error('Model for window %d does not exist.', xid)
+
+ def notify_launch(self, activity_id, service_name):
+ registry = get_registry()
+ activity_info = registry.get_bundle(service_name)
+ if not activity_info:
+ raise ValueError("Activity service name '%s'" \
+ " was not found in the bundle registry."
+ % service_name)
+ home_activity = Activity(activity_info, activity_id)
+ self._add_activity(home_activity)
+
+ self._set_active_activity(home_activity)
+
+ self.emit('launch-started', home_activity)
+
+ # FIXME: better learn about finishing processes by receiving a signal.
+ # Now just check whether an activity has a window after ~90sec
+ gobject.timeout_add_seconds(90, self._check_activity_launched,
+ activity_id)
+
+ def notify_launch_failed(self, activity_id):
+ home_activity = self.get_activity_by_id(activity_id)
+ if home_activity:
+ logging.debug("Activity %s (%s) launch failed", activity_id,
+ home_activity.get_type())
+ if self.get_launcher(activity_id) is not None:
+ self.emit('launch-failed', home_activity)
+ else:
+ # activity sent failure notification after closing launcher
+ self._remove_activity(home_activity)
+ else:
+ logging.error('Model for activity id %s does not exist.',
+ activity_id)
+
+ def _check_activity_launched(self, activity_id):
+ home_activity = self.get_activity_by_id(activity_id)
+
+ if not home_activity:
+ logging.debug('Activity %s has been closed already.', activity_id)
+ return False
+
+ if self.get_launcher(activity_id) is not None:
+ logging.debug('Activity %s still launching, assuming it failed.',
+ activity_id)
+ self.notify_launch_failed(activity_id)
+ return False
+
+
+_model = None
+
+def get_model():
+ global _model
+ if _model is None:
+ _model = ShellModel()
+ return _model
+
diff --git a/shell/src/jarabe/model/sound.py b/shell/src/jarabe/model/sound.py
new file mode 100644
index 0000000..65090a4
--- /dev/null
+++ b/shell/src/jarabe/model/sound.py
@@ -0,0 +1,58 @@
+# Copyright (C) 2006-2008 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gconf
+
+from sugar import env
+from sugar import _sugarext
+from sugar import dispatch
+
+VOLUME_STEP = 10
+
+muted_changed = dispatch.Signal()
+volume_changed = dispatch.Signal()
+
+def get_muted():
+ return _volume.get_mute()
+
+def get_volume():
+ return _volume.get_volume()
+
+def set_volume(new_volume):
+ old_volume = _volume.get_volume()
+ _volume.set_volume(new_volume)
+
+ volume_changed.send(None)
+ save()
+
+def set_muted(new_state):
+ old_state = _volume.get_mute()
+ _volume.set_mute(new_state)
+
+ muted_changed.send(None)
+ save()
+
+def save():
+ if env.is_emulator() is False:
+ client = gconf.client_get_default()
+ client.set_int('/desktop/sugar/sound/volume', get_volume())
+
+def restore():
+ if env.is_emulator() is False:
+ client = gconf.client_get_default()
+ set_volume(client.get_int('/desktop/sugar/sound/volume'))
+
+_volume = _sugarext.VolumeAlsa()
diff --git a/shell/src/jarabe/model/telepathyclient.py b/shell/src/jarabe/model/telepathyclient.py
new file mode 100644
index 0000000..f4eccc3
--- /dev/null
+++ b/shell/src/jarabe/model/telepathyclient.py
@@ -0,0 +1,100 @@
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import dbus
+from dbus import PROPERTIES_IFACE
+from telepathy.interfaces import CLIENT, \
+ CLIENT_APPROVER, \
+ CLIENT_HANDLER, \
+ CLIENT_INTERFACE_REQUESTS
+from telepathy.server import DBusProperties
+
+from sugar import dispatch
+
+SUGAR_CLIENT_SERVICE = 'org.freedesktop.Telepathy.Client.Sugar'
+SUGAR_CLIENT_PATH = '/org/freedesktop/Telepathy/Client/Sugar'
+
+class TelepathyClient(dbus.service.Object, DBusProperties):
+ def __init__(self):
+ self._interfaces = set([CLIENT, CLIENT_HANDLER,
+ CLIENT_INTERFACE_REQUESTS, PROPERTIES_IFACE,
+ CLIENT_APPROVER])
+
+ bus = dbus.Bus()
+ bus_name = dbus.service.BusName(SUGAR_CLIENT_SERVICE, bus=bus)
+
+ dbus.service.Object.__init__(self, bus_name, SUGAR_CLIENT_PATH)
+ DBusProperties.__init__(self)
+
+ self._implement_property_get(CLIENT, {
+ 'Interfaces': lambda: list(self._interfaces),
+ })
+ self._implement_property_get(CLIENT_HANDLER, {
+ 'HandlerChannelFilter': self.__get_filters_cb,
+ })
+ self._implement_property_get(CLIENT_APPROVER, {
+ 'ApproverChannelFilter': self.__get_filters_cb,
+ })
+
+ self.got_channel = dispatch.Signal()
+ self.got_dispatch_operation = dispatch.Signal()
+
+ def __get_filters_cb(self):
+ logging.debug('__get_filters_cb')
+ filter_dict = dbus.Dictionary({}, signature='sv')
+ return dbus.Array([filter_dict], signature='a{sv}')
+
+ @dbus.service.method(dbus_interface=CLIENT_HANDLER,
+ in_signature='ooa(oa{sv})aota{sv}', out_signature='')
+ def HandleChannels(self, account, connection, channels, requests_satisfied,
+ user_action_time, handler_info):
+ logging.debug('HandleChannels\n%r\n%r\n%r\n%r\n%r\n%r\n', account,
+ connection, channels, requests_satisfied,
+ user_action_time, handler_info)
+ for channel in channels:
+ self.got_channel.send(self, account=account,
+ connection=connection, channel=channel)
+
+ @dbus.service.method(dbus_interface=CLIENT_INTERFACE_REQUESTS,
+ in_signature='oa{sv}', out_signature='')
+ def AddRequest(self, request, properties):
+ logging.debug('AddRequest\n%r\n%r', request, properties)
+
+ @dbus.service.method(dbus_interface=CLIENT_APPROVER,
+ in_signature='a(oa{sv})oa{sv}', out_signature='',
+ async_callbacks=('success_cb', 'error_cb_'))
+ def AddDispatchOperation(self, channels, dispatch_operation_path,
+ properties, success_cb, error_cb_):
+ success_cb()
+ try:
+ logging.debug('AddDispatchOperation\n%r\n%r\n%r', channels,
+ dispatch_operation_path, properties)
+
+ self.got_dispatch_operation.send(self, channels=channels,
+ dispatch_operation_path=dispatch_operation_path,
+ properties=properties)
+ except Exception, e:
+ logging.exception(e)
+
+_instance = None
+
+def get_instance():
+ global _instance
+ if not _instance:
+ _instance = TelepathyClient()
+ return _instance
diff --git a/shell/src/jarabe/util/Makefile.am b/shell/src/jarabe/util/Makefile.am
new file mode 100644
index 0000000..8bda3d6
--- /dev/null
+++ b/shell/src/jarabe/util/Makefile.am
@@ -0,0 +1,7 @@
+SUBDIRS = \
+ telepathy
+
+sugardir = $(pythondir)/jarabe/util
+sugar_PYTHON = \
+ __init__.py \
+ emulator.py
diff --git a/shell/src/jarabe/util/__init__.py b/shell/src/jarabe/util/__init__.py
new file mode 100644
index 0000000..1610dd0
--- /dev/null
+++ b/shell/src/jarabe/util/__init__.py
@@ -0,0 +1,19 @@
+"""OLPC Sugar Jarabe utility modules
+"""
+
+# Copyright (C) 2008, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
diff --git a/shell/src/jarabe/util/emulator.py b/shell/src/jarabe/util/emulator.py
new file mode 100644
index 0000000..5a99dbe
--- /dev/null
+++ b/shell/src/jarabe/util/emulator.py
@@ -0,0 +1,177 @@
+# Copyright (C) 2006-2008, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import signal
+import subprocess
+import sys
+import time
+from optparse import OptionParser
+
+import gtk
+import gobject
+
+from sugar import env
+
+
+ERROR_NO_DISPLAY = 30
+ERROR_NO_SERVER = 31
+
+
+default_dimensions = (800, 600)
+def _run_xephyr(display, dpi, dimensions, fullscreen):
+ cmd = [ 'Xephyr' ]
+ cmd.append(':%d' % display)
+ cmd.append('-ac')
+
+ screen_size = (gtk.gdk.screen_width(), gtk.gdk.screen_height())
+
+ if (not dimensions) and (fullscreen is None) and \
+ (screen_size < default_dimensions) :
+ # no forced settings, screen too small => fit screen
+ fullscreen = True
+ elif (not dimensions) :
+ # screen is big enough or user has en/disabled fullscreen manually
+ # => use default size (will get ignored for fullscreen)
+ dimensions = '%dx%d' % default_dimensions
+
+ if not dpi :
+ dpi = gtk.settings_get_default().get_property('gtk-xft-dpi') / 1024
+
+ if fullscreen :
+ cmd.append('-fullscreen')
+
+ if dimensions :
+ cmd.append('-screen')
+ cmd.append(dimensions)
+
+ if dpi :
+ cmd.append('-dpi')
+ cmd.append('%d' % dpi)
+
+ cmd.append('-noreset')
+
+ try:
+ pipe = subprocess.Popen(cmd)
+
+ except OSError, exc:
+ sys.stderr.write('Error executing server: %s\n' % (exc, ))
+ return None
+
+ return pipe
+
+
+def _check_server(display):
+ result = subprocess.call(['xdpyinfo', '-display', ':%d' % display],
+ stdout=open(os.devnull, "w"),
+ stderr=open(os.devnull, "w"))
+ return result == 0
+
+
+def _kill_pipe(pipe):
+ """Terminate and wait for child process."""
+ try:
+ os.kill(pipe.pid, signal.SIGTERM)
+ except OSError:
+ pass
+
+ pipe.wait()
+
+
+def _start_xephyr(dpi, dimensions, fullscreen):
+ for display in range(30, 40):
+ if not _check_server(display):
+ pipe = _run_xephyr(display, dpi, dimensions, fullscreen)
+ if pipe is None:
+ return None, None
+
+ for i_ in range(10):
+ if _check_server(display):
+ return pipe, display
+
+ time.sleep(0.1)
+
+ _kill_pipe(pipe)
+
+ return None, None
+
+
+def _start_window_manager():
+ cmd = ['metacity']
+
+ cmd.extend(['--no-force-fullscreen'])
+
+ gobject.spawn_async(cmd, flags=gobject.SPAWN_SEARCH_PATH)
+
+def _setup_env(display, scaling, emulator_pid):
+ os.environ['SUGAR_EMULATOR'] = 'yes'
+ os.environ['GABBLE_LOGFILE'] = os.path.join(
+ env.get_profile_path(), 'logs', 'telepathy-gabble.log')
+ os.environ['SALUT_LOGFILE'] = os.path.join(
+ env.get_profile_path(), 'logs', 'telepathy-salut.log')
+ os.environ['STREAM_ENGINE_LOGFILE'] = os.path.join(
+ env.get_profile_path(), 'logs', 'telepathy-stream-engine.log')
+ os.environ['DISPLAY'] = ":%d" % (display)
+ os.environ['SUGAR_EMULATOR_PID'] = emulator_pid
+
+ if scaling:
+ os.environ['SUGAR_SCALING'] = scaling
+
+def main():
+ """Script-level operations"""
+
+ parser = OptionParser()
+ parser.add_option('-d', '--dpi', dest='dpi', type="int",
+ help='Emulator dpi')
+ parser.add_option('-s', '--scaling', dest='scaling',
+ help='Sugar scaling in %')
+ parser.add_option('-i', '--dimensions', dest='dimensions',
+ help='Emulator dimensions (ex. 1200x900)')
+ parser.add_option('-f', '--fullscreen', dest='fullscreen',
+ action='store_true', default=None,
+ help='Run emulator in fullscreen mode')
+ parser.add_option('-F', '--no-fullscreen', dest='fullscreen',
+ action='store_false',
+ help='Do not run emulator in fullscreen mode')
+ (options, args) = parser.parse_args()
+
+ if not os.environ.get('DISPLAY'):
+ sys.stderr.write('DISPLAY not set, cannot connect to host X server.\n')
+ return ERROR_NO_DISPLAY
+
+ server, display = _start_xephyr(options.dpi, options.dimensions,
+ options.fullscreen)
+ if server is None:
+ sys.stderr.write('Failed to start server. Please check output above'
+ ' for any error message.\n')
+ return ERROR_NO_SERVER
+
+ _setup_env(display, options.scaling, str(server.pid))
+
+ command = ['dbus-launch', '--exit-with-session']
+
+ if not args:
+ command.append('sugar')
+ else:
+ _start_window_manager()
+
+ if args[0].endswith('.py'):
+ command.append('python')
+
+ command.append(args[0])
+
+ subprocess.call(command)
+ _kill_pipe(server)
diff --git a/shell/src/jarabe/util/telepathy/Makefile.am b/shell/src/jarabe/util/telepathy/Makefile.am
new file mode 100644
index 0000000..d40349d
--- /dev/null
+++ b/shell/src/jarabe/util/telepathy/Makefile.am
@@ -0,0 +1,4 @@
+sugardir = $(pythondir)/jarabe/util/telepathy
+sugar_PYTHON = \
+ __init__.py \
+ connection_watcher.py
diff --git a/shell/src/jarabe/util/telepathy/__init__.py b/shell/src/jarabe/util/telepathy/__init__.py
new file mode 100644
index 0000000..387d09c
--- /dev/null
+++ b/shell/src/jarabe/util/telepathy/__init__.py
@@ -0,0 +1,19 @@
+"""OLPC Sugar Jarabe utility telepathy modules
+"""
+
+# Copyright (C) 2008, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
diff --git a/shell/src/jarabe/util/telepathy/connection_watcher.py b/shell/src/jarabe/util/telepathy/connection_watcher.py
new file mode 100644
index 0000000..391bdd5
--- /dev/null
+++ b/shell/src/jarabe/util/telepathy/connection_watcher.py
@@ -0,0 +1,118 @@
+# This should eventually land in telepathy-python, so has the same license:
+# Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# FIXME: this sould go upstream, in telepathy-python
+
+import logging
+
+import dbus
+import dbus.mainloop.glib
+import gobject
+
+from telepathy.client import Connection
+from telepathy.interfaces import CONN_INTERFACE
+from telepathy.constants import CONNECTION_STATUS_CONNECTED, \
+ CONNECTION_STATUS_DISCONNECTED
+
+class ConnectionWatcher(gobject.GObject):
+ __gsignals__ = {
+ 'connection-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'connection-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, bus=None):
+ gobject.GObject.__init__(self)
+
+ if bus is None:
+ self.bus = dbus.Bus()
+ else:
+ self.bus = bus
+
+ # D-Bus path -> Connection
+ self._connections = {}
+
+ self.bus.add_signal_receiver(self._status_changed_cb,
+ dbus_interface=CONN_INTERFACE, signal_name='StatusChanged',
+ path_keyword='path')
+
+ for conn in Connection.get_connections(bus):
+ conn.call_when_ready(self._conn_ready_cb)
+
+ def _status_changed_cb(self, *args, **kwargs):
+ path = kwargs['path']
+ if not path.startswith('/org/freedesktop/Telepathy/Connection/'):
+ return
+
+ status, reason_ = args
+ service_name = path.replace('/', '.')[1:]
+
+ if status == CONNECTION_STATUS_CONNECTED:
+ self._add_connection(service_name, path)
+ elif status == CONNECTION_STATUS_DISCONNECTED:
+ self._remove_connection(service_name, path)
+
+ def _conn_ready_cb(self, conn):
+ if conn.object_path in self._connections:
+ return
+
+ self._connections[conn.object_path] = conn
+ self.emit('connection-added', conn)
+
+ def _add_connection(self, service_name, path):
+ if path in self._connections:
+ return
+
+ try:
+ Connection(service_name, path, ready_handler=self._conn_ready_cb)
+ except dbus.exceptions.DBusException:
+ logging.debug('%s is propably already gone.', service_name)
+
+ def _remove_connection(self, service_name, path):
+ conn = self._connections.pop(path, None)
+ if conn is None:
+ return
+
+ self.emit('connection-removed', conn)
+
+ def get_connections(self):
+ return self._connections.values()
+
+_instance = None
+
+def get_instance():
+ global _instance
+ if _instance is None:
+ _instance = ConnectionWatcher()
+ return _instance
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ def connection_added_cb(conn_watcher, conn):
+ print "new connection", conn.service_name
+
+ def connection_removed_cb(conn_watcher, conn):
+ print "removed connection", conn.service_name
+
+ watcher = ConnectionWatcher()
+ watcher.connect('connection-added', connection_added_cb)
+ watcher.connect('connection-removed', connection_removed_cb)
+
+ loop = gobject.MainLoop()
+ loop.run()
diff --git a/shell/src/jarabe/view/Makefile.am b/shell/src/jarabe/view/Makefile.am
new file mode 100644
index 0000000..1abea6d
--- /dev/null
+++ b/shell/src/jarabe/view/Makefile.am
@@ -0,0 +1,12 @@
+sugardir = $(pythondir)/jarabe/view
+sugar_PYTHON = \
+ __init__.py \
+ buddyicon.py \
+ buddymenu.py \
+ keyhandler.py \
+ launcher.py \
+ palettes.py \
+ pulsingicon.py \
+ service.py \
+ tabbinghandler.py \
+ viewsource.py
diff --git a/shell/src/jarabe/view/__init__.py b/shell/src/jarabe/view/__init__.py
new file mode 100644
index 0000000..a9dd95a
--- /dev/null
+++ b/shell/src/jarabe/view/__init__.py
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
diff --git a/shell/src/jarabe/view/buddyicon.py b/shell/src/jarabe/view/buddyicon.py
new file mode 100644
index 0000000..37b9167
--- /dev/null
+++ b/shell/src/jarabe/view/buddyicon.py
@@ -0,0 +1,61 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from sugar.graphics.icon import CanvasIcon
+from sugar.graphics import style
+
+from jarabe.view.buddymenu import BuddyMenu
+
+class BuddyIcon(CanvasIcon):
+ def __init__(self, buddy, size=style.STANDARD_ICON_SIZE):
+ CanvasIcon.__init__(self, icon_name='computer-xo', size=size)
+
+ self._greyed_out = False
+ self._buddy = buddy
+ self._buddy.connect('notify::present', self.__buddy_notify_present_cb)
+ self._buddy.connect('notify::color', self.__buddy_notify_color_cb)
+
+ self._update_color()
+
+ def create_palette(self):
+ return BuddyMenu(self._buddy)
+
+ def __buddy_notify_present_cb(self, buddy, pspec):
+ # Update the icon's color when the buddy comes and goes
+ self._update_color()
+
+ def __buddy_notify_color_cb(self, buddy, pspec):
+ self._update_color()
+
+ def _update_color(self):
+ # keep the icon in the palette in sync with the view
+ palette = self.get_palette()
+ if self._greyed_out:
+ self.props.stroke_color = '#D5D5D5'
+ self.props.fill_color = style.COLOR_TRANSPARENT.get_svg()
+ if palette is not None:
+ palette.props.icon.props.stroke_color = self.props.stroke_color
+ palette.props.icon.props.fill_color = self.props.fill_color
+ else:
+ self.props.xo_color = self._buddy.get_color()
+ if palette is not None:
+ palette.props.icon.props.xo_color = self._buddy.get_color()
+
+ def set_filter(self, query):
+ self._greyed_out = (self._buddy.get_nick().lower().find(query) == -1) \
+ and not self._buddy.is_owner()
+ self._update_color()
+
diff --git a/shell/src/jarabe/view/buddymenu.py b/shell/src/jarabe/view/buddymenu.py
new file mode 100644
index 0000000..0ba6cc1
--- /dev/null
+++ b/shell/src/jarabe/view/buddymenu.py
@@ -0,0 +1,168 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+
+import gtk
+import gconf
+import dbus
+
+from sugar.graphics.palette import Palette
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.icon import Icon
+
+from jarabe.model import shell
+from jarabe.model import friends
+from jarabe.model.session import get_session_manager
+from jarabe.controlpanel.gui import ControlPanel
+
+class BuddyMenu(Palette):
+ def __init__(self, buddy):
+ self._buddy = buddy
+
+ buddy_icon = Icon(icon_name='computer-xo',
+ xo_color=buddy.get_color(),
+ icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
+ Palette.__init__(self, None, primary_text=buddy.get_nick(),
+ icon=buddy_icon)
+ self._invite_menu = None
+ self._active_activity_changed_hid = None
+ self.connect('destroy', self.__destroy_cb)
+
+ self._buddy.connect('notify::nick', self.__buddy_notify_nick_cb)
+
+ if buddy.is_owner():
+ self._add_my_items()
+ else:
+ self._add_buddy_items()
+
+ def __destroy_cb(self, menu):
+ if self._active_activity_changed_hid is not None:
+ home_model = shell.get_model()
+ home_model.disconnect(self._active_activity_changed_hid)
+ self._buddy.disconnect_by_func(self.__buddy_notify_nick_cb)
+
+ def _add_buddy_items(self):
+ if friends.get_model().has_buddy(self._buddy):
+ menu_item = MenuItem(_('Remove friend'), 'list-remove')
+ menu_item.connect('activate', self._remove_friend_cb)
+ else:
+ menu_item = MenuItem(_('Make friend'), 'list-add')
+ menu_item.connect('activate', self._make_friend_cb)
+
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ self._invite_menu = MenuItem('')
+ self._invite_menu.connect('activate', self._invite_friend_cb)
+ self.menu.append(self._invite_menu)
+
+ home_model = shell.get_model()
+ self._active_activity_changed_hid = home_model.connect(
+ 'active-activity-changed', self._cur_activity_changed_cb)
+ activity = home_model.get_active_activity()
+ self._update_invite_menu(activity)
+
+ def _add_my_items(self):
+ item = MenuItem(_('Shutdown'), 'system-shutdown')
+ item.connect('activate', self.__shutdown_activate_cb)
+ self.menu.append(item)
+ item.show()
+
+ client = gconf.client_get_default()
+
+ if client.get_bool('/desktop/sugar/show_logout'):
+ item = MenuItem(_('Logout'), 'system-logout')
+ item.connect('activate', self.__logout_activate_cb)
+ self.menu.append(item)
+ item.show()
+
+ item = MenuItem(_('My Settings'), 'preferences-system')
+ item.connect('activate', self.__controlpanel_activate_cb)
+ self.menu.append(item)
+ item.show()
+
+ def __logout_activate_cb(self, menu_item):
+ session_manager = get_session_manager()
+ session_manager.logout()
+
+ def __reboot_activate_cb(self, menu_item):
+ session_manager = get_session_manager()
+ session_manager.reboot()
+
+ def __shutdown_activate_cb(self, menu_item):
+ session_manager = get_session_manager()
+ session_manager.shutdown()
+
+ def __controlpanel_activate_cb(self, menu_item):
+ panel = ControlPanel()
+ panel.set_transient_for(self.get_toplevel())
+ panel.show()
+
+ def _update_invite_menu(self, activity):
+ buddy_activity = self._buddy.props.current_activity
+ if buddy_activity is not None:
+ buddy_activity_id = buddy_activity.activity_id
+ else:
+ buddy_activity_id = None
+
+ if activity is None or activity.is_journal() or \
+ activity.get_activity_id() == buddy_activity_id:
+ self._invite_menu.hide()
+ else:
+ title = activity.get_title()
+ label = self._invite_menu.get_children()[0]
+ label.set_text(_('Invite to %s') % title)
+
+ icon = Icon(file=activity.get_icon_path())
+ icon.props.xo_color = activity.get_icon_color()
+ self._invite_menu.set_image(icon)
+ icon.show()
+
+ self._invite_menu.show()
+
+ def _cur_activity_changed_cb(self, home_model, activity_model):
+ self._update_invite_menu(activity_model)
+
+ def __buddy_notify_nick_cb(self, buddy, pspec):
+ self.set_primary_text(buddy.props.nick)
+
+ def _make_friend_cb(self, menuitem):
+ friends.get_model().make_friend(self._buddy)
+
+ def _remove_friend_cb(self, menuitem):
+ friends.get_model().remove(self._buddy)
+
+ def _invite_friend_cb(self, menuitem):
+ activity = shell.get_model().get_active_activity()
+ service = activity.get_service()
+ if service:
+ try:
+ service.InviteContact(self._buddy.props.account,
+ self._buddy.props.contact_id)
+ except dbus.DBusException, e:
+ expected_exceptions = [
+ 'org.freedesktop.DBus.Error.UnknownMethod',
+ 'org.freedesktop.DBus.Python.NotImplementedError']
+ if e.get_dbus_name() in expected_exceptions:
+ logging.warning('Trying deprecated Activity.Invite')
+ service.Invite(self._buddy.props.key)
+ else:
+ raise
+ else:
+ logging.error('Invite failed, activity service not ')
diff --git a/shell/src/jarabe/view/keyhandler.py b/shell/src/jarabe/view/keyhandler.py
new file mode 100644
index 0000000..8a85ac7
--- /dev/null
+++ b/shell/src/jarabe/view/keyhandler.py
@@ -0,0 +1,242 @@
+# Copyright (C) 2006-2007, Red Hat, Inc.
+# Copyright (C) 2009 Simon Schampijer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+import traceback
+
+import dbus
+import gtk
+
+from sugar._sugarext import KeyGrabber
+
+from jarabe.model import sound
+from jarabe.model import shell
+from jarabe.model import session
+from jarabe.view.tabbinghandler import TabbingHandler
+from jarabe.model.shell import ShellModel
+from jarabe import config
+from jarabe.journal import journalactivity
+
+_VOLUME_STEP = sound.VOLUME_STEP
+_VOLUME_MAX = 100
+_TABBING_MODIFIER = gtk.gdk.MOD1_MASK
+
+_actions_table = {
+ 'F1' : 'zoom_mesh',
+ 'F2' : 'zoom_group',
+ 'F3' : 'zoom_home',
+ 'F4' : 'zoom_activity',
+ 'F5' : 'open_search',
+ 'F6' : 'frame',
+ 'XF86AudioMute' : 'volume_mute',
+ 'F11' : 'volume_down',
+ 'XF86AudioLowerVolume' : 'volume_down',
+ 'F12' : 'volume_up',
+ 'XF86AudioRaiseVolume' : 'volume_up',
+ '<alt>F11' : 'volume_min',
+ '<alt>F12' : 'volume_max',
+ '0x93' : 'frame',
+ '<alt>Tab' : 'next_window',
+ '<alt><shift>Tab' : 'previous_window',
+ '<alt>Escape' : 'close_window',
+ '0xDC' : 'open_search',
+# the following are intended for emulator users
+ '<alt><shift>f' : 'frame',
+ '<alt><shift>q' : 'quit_emulator',
+ 'XF86Search' : 'open_search',
+ '<alt><shift>o' : 'open_search',
+ '<alt><shift>s' : 'say_text',
+}
+
+SPEECH_DBUS_SERVICE = 'org.laptop.Speech'
+SPEECH_DBUS_PATH = '/org/laptop/Speech'
+SPEECH_DBUS_INTERFACE = 'org.laptop.Speech'
+
+class KeyHandler(object):
+ def __init__(self, frame):
+ self._frame = frame
+ self._key_pressed = None
+ self._keycode_pressed = 0
+ self._keystate_pressed = 0
+ self._speech_proxy = None
+
+ self._key_grabber = KeyGrabber()
+ self._key_grabber.connect('key-pressed',
+ self._key_pressed_cb)
+ self._key_grabber.connect('key-released',
+ self._key_released_cb)
+
+ self._tabbing_handler = TabbingHandler(self._frame, _TABBING_MODIFIER)
+
+ for f in os.listdir(os.path.join(config.ext_path, 'globalkey')):
+ if f.endswith('.py') and not f.startswith('__'):
+ module_name = f[:-3]
+ try:
+ logging.debug('Loading module %r', module_name)
+ module = __import__('globalkey.' + module_name, globals(),
+ locals(), [module_name])
+ for key in module.BOUND_KEYS:
+ if key in _actions_table:
+ raise ValueError('Key %r is already bound' % key)
+ _actions_table[key] = module
+ except Exception:
+ logging.error('Exception while loading extension:\n' + \
+ traceback.format_exc())
+
+ self._key_grabber.grab_keys(_actions_table.keys())
+
+ def _change_volume(self, step=None, value=None):
+ if step is not None:
+ volume = sound.get_volume() + step
+ elif value is not None:
+ volume = value
+
+ volume = min(max(0, volume), _VOLUME_MAX)
+
+ sound.set_volume(volume)
+ sound.set_muted(volume == 0)
+
+ def _get_speech_proxy(self):
+ if self._speech_proxy is None:
+ bus = dbus.SessionBus()
+ speech_obj = bus.get_object(SPEECH_DBUS_SERVICE, SPEECH_DBUS_PATH,
+ follow_name_owner_changes=True)
+ self._speech_proxy = dbus.Interface(speech_obj,
+ SPEECH_DBUS_INTERFACE)
+ return self._speech_proxy
+
+ def _on_speech_err(self, ex):
+ logging.error('An error occurred with the ESpeak service: %r', ex)
+
+ def _primary_selection_cb(self, clipboard, text, user_data):
+ logging.debug('KeyHandler._primary_selection_cb: %r', text)
+ if text:
+ self._get_speech_proxy().SayText(text, reply_handler=lambda: None, \
+ error_handler=self._on_speech_err)
+
+ def handle_say_text(self, event_time):
+ clipboard = gtk.clipboard_get(selection="PRIMARY")
+ clipboard.request_text(self._primary_selection_cb)
+
+ def handle_previous_window(self, event_time):
+ self._tabbing_handler.previous_activity(event_time)
+
+ def handle_next_window(self, event_time):
+ self._tabbing_handler.next_activity(event_time)
+
+ def handle_close_window(self, event_time):
+ active_activity = shell.get_model().get_active_activity()
+ if active_activity.is_journal():
+ return
+
+ active_activity.get_window().close()
+
+ def handle_zoom_mesh(self, event_time):
+ shell.get_model().set_zoom_level(ShellModel.ZOOM_MESH, event_time)
+
+ def handle_zoom_group(self, event_time):
+ shell.get_model().set_zoom_level(ShellModel.ZOOM_GROUP, event_time)
+
+ def handle_zoom_home(self, event_time):
+ shell.get_model().set_zoom_level(ShellModel.ZOOM_HOME, event_time)
+
+ def handle_zoom_activity(self, event_time):
+ shell.get_model().set_zoom_level(ShellModel.ZOOM_ACTIVITY, event_time)
+
+ def handle_volume_max(self, event_time):
+ self._change_volume(value=_VOLUME_MAX)
+
+ def handle_volume_min(self, event_time):
+ self._change_volume(value=0)
+
+ def handle_volume_mute(self, event_time):
+ if sound.get_muted() is True:
+ sound.set_muted(False)
+ else:
+ sound.set_muted(True)
+
+ def handle_volume_up(self, event_time):
+ self._change_volume(step=_VOLUME_STEP)
+
+ def handle_volume_down(self, event_time):
+ self._change_volume(step=-_VOLUME_STEP)
+
+ def handle_frame(self, event_time):
+ self._frame.notify_key_press()
+
+ def handle_quit_emulator(self, event_time):
+ session.get_session_manager().shutdown()
+
+ def handle_open_search(self, event_time):
+ journalactivity.get_journal().focus_search()
+
+ def _key_pressed_cb(self, grabber, keycode, state, event_time):
+ key = grabber.get_key(keycode, state)
+ logging.debug('_key_pressed_cb: %i %i %s', keycode, state, key)
+ if key is not None:
+ self._key_pressed = key
+ self._keycode_pressed = keycode
+ self._keystate_pressed = state
+
+ action = _actions_table[key]
+ if self._tabbing_handler.is_tabbing():
+ # Only accept window tabbing events, everything else
+ # cancels the tabbing operation.
+ if not action in ["next_window", "previous_window"]:
+ self._tabbing_handler.stop(event_time)
+ return True
+
+ if hasattr(action, 'handle_key_press'):
+ action.handle_key_press(key)
+ elif isinstance(action, basestring):
+ method = getattr(self, 'handle_' + action)
+ method(event_time)
+ else:
+ raise TypeError('Invalid action %r' % action)
+
+ return True
+ else:
+ # If this is not a registered key, then cancel tabbing.
+ if self._tabbing_handler.is_tabbing():
+ if not grabber.is_modifier(keycode):
+ self._tabbing_handler.stop(event_time)
+ return True
+
+ return False
+
+ def _key_released_cb(self, grabber, keycode, state, event_time):
+ logging.debug('_key_released_cb: %i %i' % (keycode, state))
+ if self._tabbing_handler.is_tabbing():
+ # We stop tabbing and switch to the new window as soon as the
+ # modifier key is raised again.
+ if grabber.is_modifier(keycode, mask=_TABBING_MODIFIER):
+ self._tabbing_handler.stop(event_time)
+
+ return True
+ return False
+
+_instance = None
+
+def setup(frame):
+ global _instance
+
+ if _instance:
+ del _instance
+
+ _instance = KeyHandler(frame)
+
diff --git a/shell/src/jarabe/view/launcher.py b/shell/src/jarabe/view/launcher.py
new file mode 100644
index 0000000..89251e5
--- /dev/null
+++ b/shell/src/jarabe/view/launcher.py
@@ -0,0 +1,217 @@
+# Copyright (C) 2008, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+from gettext import gettext as _
+
+import gtk
+import hippo
+import gobject
+
+from sugar import wm
+from sugar.graphics import style
+from sugar.graphics import animator
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.model import shell
+from jarabe.view.pulsingicon import CanvasPulsingIcon
+
+
+class LaunchWindow(gtk.Window):
+
+ def __init__(self, activity_id, icon_path, icon_color):
+ gobject.GObject.__init__(self)
+
+ self.props.type_hint = gtk.gdk.WINDOW_TYPE_HINT_NORMAL
+ self.props.decorated = False
+ self.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color())
+
+ canvas = gtk.VBox()
+ canvas.show()
+ self.add(canvas)
+
+ bar_size = gtk.gdk.screen_height() / 5 * 2
+
+ header = gtk.VBox()
+ header.set_size_request(-1, bar_size)
+ header.show()
+ canvas.pack_start(header, expand=False)
+
+ self._activity_id = activity_id
+ self._box = LaunchBox(activity_id, icon_path, icon_color)
+ box = hippo.Canvas()
+ box.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color())
+ box.set_root(self._box)
+ box.show()
+ canvas.pack_start(box)
+
+ footer = gtk.VBox(spacing=style.DEFAULT_SPACING)
+ footer.set_size_request(-1, bar_size)
+ footer.show()
+ canvas.pack_end(footer, expand=False)
+
+ self.error_text = gtk.Label()
+ self.error_text.props.use_markup = True
+ footer.pack_start(self.error_text, expand=False)
+
+ button_box = gtk.Alignment(xalign=0.5)
+ button_box.show()
+ footer.pack_start(button_box, expand=False)
+ self.cancel_button = gtk.Button(stock=gtk.STOCK_STOP)
+ button_box.add(self.cancel_button)
+
+ self.connect('realize', self.__realize_cb)
+
+ screen = gtk.gdk.screen_get_default()
+ screen.connect('size-changed', self.__size_changed_cb)
+
+ self._update_size()
+
+ def show(self):
+ self.present()
+ self._box.zoom_in()
+
+ def _update_size(self):
+ self.resize(gtk.gdk.screen_width(), gtk.gdk.screen_height())
+
+ def __realize_cb(self, widget):
+ wm.set_activity_id(widget.window, str(self._activity_id))
+ widget.window.property_change('_SUGAR_WINDOW_TYPE', 'STRING', 8,
+ gtk.gdk.PROP_MODE_REPLACE, 'launcher')
+
+ def __size_changed_cb(self, screen):
+ self._update_size()
+
+
+class LaunchBox(hippo.CanvasBox):
+
+ def __init__(self, activity_id, icon_path, icon_color):
+ gobject.GObject.__init__(self, orientation=hippo.ORIENTATION_VERTICAL)
+
+ self._activity_id = activity_id
+ self._activity_icon = CanvasPulsingIcon(
+ file_name=icon_path,
+ pulse_color=icon_color,
+ background_color=style.COLOR_WHITE.get_gdk_color())
+ self.append(self._activity_icon, hippo.PACK_EXPAND)
+
+ # FIXME support non-xo colors in CanvasPulsingIcon
+ self._activity_icon.props.base_color = \
+ XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+
+ self._animator = animator.Animator(1.0)
+
+ self._home = shell.get_model()
+ self._home.connect('active-activity-changed',
+ self.__active_activity_changed_cb)
+
+ self.connect('destroy', self.__destroy_cb)
+
+ def __destroy_cb(self, box):
+ self._activity_icon.props.pulsing = False
+ self._home.disconnect_by_func(self.__active_activity_changed_cb)
+
+ def zoom_in(self):
+ self._activity_icon.props.size = style.STANDARD_ICON_SIZE
+
+ self._animator.remove_all()
+ self._animator.add(_Animation(self._activity_icon,
+ style.STANDARD_ICON_SIZE,
+ style.XLARGE_ICON_SIZE))
+ self._animator.start()
+ self._activity_icon.props.pulsing = True
+
+ def __active_activity_changed_cb(self, model, activity):
+ if activity.get_activity_id() == self._activity_id:
+ self._activity_icon.props.paused = False
+ else:
+ self._activity_icon.props.paused = True
+
+
+class _Animation(animator.Animation):
+
+ def __init__(self, icon, start_size, end_size):
+ animator.Animation.__init__(self, 0.0, 1.0)
+
+ self._icon = icon
+ self.start_size = start_size
+ self.end_size = end_size
+
+ def next_frame(self, current):
+ d = (self.end_size - self.start_size) * current
+ self._icon.props.size = int(self.start_size + d)
+
+
+def setup():
+ model = shell.get_model()
+ model.connect('launch-started', __launch_started_cb)
+ model.connect('launch-failed', __launch_failed_cb)
+ model.connect('launch-completed', __launch_completed_cb)
+
+
+def add_launcher(activity_id, icon_path, icon_color):
+ model = shell.get_model()
+
+ if model.get_launcher(activity_id) is not None:
+ return
+
+ launch_window = LaunchWindow(activity_id, icon_path, icon_color)
+ launch_window.show()
+
+ model.register_launcher(activity_id, launch_window)
+
+
+def __launch_started_cb(home_model, home_activity):
+ add_launcher(home_activity.get_activity_id(),
+ home_activity.get_icon_path(), home_activity.get_icon_color())
+
+
+def __launch_failed_cb(home_model, home_activity):
+ activity_id = home_activity.get_activity_id()
+ launcher = shell.get_model().get_launcher(activity_id)
+
+ if launcher is None:
+ logging.error('Launcher for %s is missing', activity_id)
+ else:
+ launcher.error_text.props.label = _('<b>%s</b> failed to start.') % \
+ home_activity.get_activity_name()
+ launcher.error_text.show()
+
+ launcher.cancel_button.connect('clicked',
+ __cancel_button_clicked_cb, home_activity)
+ launcher.cancel_button.show()
+
+
+def __cancel_button_clicked_cb(button, home_activity):
+ _destroy_launcher(home_activity)
+
+
+def __launch_completed_cb(home_model, home_activity):
+ _destroy_launcher(home_activity)
+
+
+def _destroy_launcher(home_activity):
+ activity_id = home_activity.get_activity_id()
+
+ launcher = shell.get_model().get_launcher(activity_id)
+ if launcher is None:
+ if not home_activity.is_journal():
+ logging.error('Launcher was not registered for %s', activity_id)
+ return
+
+ shell.get_model().unregister_launcher(activity_id)
+ launcher.destroy()
diff --git a/shell/src/jarabe/view/palettes.py b/shell/src/jarabe/view/palettes.py
new file mode 100644
index 0000000..43612d4
--- /dev/null
+++ b/shell/src/jarabe/view/palettes.py
@@ -0,0 +1,250 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import statvfs
+from gettext import gettext as _
+import logging
+
+import gconf
+import gtk
+
+from sugar import env
+from sugar.graphics.palette import Palette
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.icon import Icon
+from sugar.graphics import style
+from sugar.graphics.xocolor import XoColor
+from sugar.activity import activityfactory
+from sugar.activity.activityhandle import ActivityHandle
+
+from jarabe.model import shell
+from jarabe.view.viewsource import setup_view_source
+from jarabe.journal import misc
+
+class BasePalette(Palette):
+ def __init__(self, home_activity):
+ Palette.__init__(self)
+
+ self._notify_launch_hid = None
+
+ if home_activity.props.launch_status == shell.Activity.LAUNCHING:
+ self._notify_launch_hid = home_activity.connect( \
+ 'notify::launch-status', self.__notify_launch_status_cb)
+ self.set_primary_text(_('Starting...'))
+ elif home_activity.props.launch_status == shell.Activity.LAUNCH_FAILED:
+ self._on_failed_launch()
+ else:
+ self.setup_palette()
+
+ def setup_palette(self):
+ raise NotImplementedError
+
+ def _on_failed_launch(self):
+ self.set_primary_text(_('Activity failed to start'))
+
+ def __notify_launch_status_cb(self, home_activity, pspec):
+ home_activity.disconnect(self._notify_launch_hid)
+ self._notify_launch_hid = None
+ if home_activity.props.launch_status == shell.Activity.LAUNCH_FAILED:
+ self._on_failed_launch()
+ else:
+ self.setup_palette()
+
+
+class CurrentActivityPalette(BasePalette):
+ def __init__(self, home_activity):
+ self._home_activity = home_activity
+ BasePalette.__init__(self, home_activity)
+
+ def setup_palette(self):
+ self.props.primary_text = self._home_activity.get_activity_name()
+
+ if self._home_activity.get_title() != self.props.primary_text:
+ self.props.secondary_text = self._home_activity.get_title()
+
+ menu_item = MenuItem(_('Resume'), 'activity-start')
+ menu_item.connect('activate', self.__resume_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ # TODO: share-with, keep
+
+ menu_item = MenuItem(_('View Source'), 'view-source')
+ # TODO Make this accelerator translatable
+ menu_item.props.accelerator = '<Alt><Shift>v'
+ menu_item.connect('activate', self.__view_source__cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ separator = gtk.SeparatorMenuItem()
+ self.menu.append(separator)
+ separator.show()
+
+ menu_item = MenuItem(_('Stop'), 'activity-stop')
+ menu_item.connect('activate', self.__stop_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ def __resume_activate_cb(self, menu_item):
+ self._home_activity.get_window().activate(gtk.get_current_event_time())
+
+ def __view_source__cb(self, menu_item):
+ setup_view_source(self._home_activity)
+ shell_model = shell.get_model()
+ if self._home_activity is not shell_model.get_active_activity():
+ self._home_activity.get_window().activate( \
+ gtk.get_current_event_time())
+
+ def __active_window_changed_cb(self, screen, previous_window=None):
+ setup_view_source()
+ self._screen.disconnect(self._active_window_changed_sid)
+
+ def __stop_activate_cb(self, menu_item):
+ self._home_activity.get_window().close(1)
+
+
+class ActivityPalette(Palette):
+ __gtype_name__ = 'SugarActivityPalette'
+
+ def __init__(self, activity_info):
+ self._activity_info = activity_info
+
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string("/desktop/sugar/user/color"))
+ activity_icon = Icon(file=activity_info.get_icon(),
+ xo_color=color,
+ icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
+
+ Palette.__init__(self, primary_text=activity_info.get_name(),
+ icon=activity_icon)
+
+ xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ menu_item = MenuItem(text_label=_('Start new'),
+ file_name=activity_info.get_icon(),
+ xo_color=xo_color)
+ menu_item.connect('activate', self.__start_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ # TODO: start-with
+
+ def __start_activate_cb(self, menu_item):
+ self.popdown(immediate=True)
+ misc.launch(self._activity_info)
+
+class JournalPalette(BasePalette):
+ def __init__(self, home_activity):
+ self._home_activity = home_activity
+ self._progress_bar = None
+ self._free_space_label = None
+
+ BasePalette.__init__(self, home_activity)
+
+ def setup_palette(self):
+ self.set_primary_text(self._home_activity.get_title())
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+ vbox.show()
+
+ self._progress_bar = gtk.ProgressBar()
+ vbox.add(self._progress_bar)
+ self._progress_bar.show()
+
+ self._free_space_label = gtk.Label()
+ self._free_space_label.set_alignment(0.5, 0.5)
+ vbox.add(self._free_space_label)
+ self._free_space_label.show()
+
+ self.connect('popup', self.__popup_cb)
+
+ menu_item = MenuItem(_('Show contents'))
+
+ icon = Icon(file=self._home_activity.get_icon_path(),
+ icon_size=gtk.ICON_SIZE_MENU,
+ xo_color=self._home_activity.get_icon_color())
+ menu_item.set_image(icon)
+ icon.show()
+
+ menu_item.connect('activate', self.__open_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ def __open_activate_cb(self, menu_item):
+ self._home_activity.get_window().activate(gtk.get_current_event_time())
+
+ def __popup_cb(self, palette):
+ stat = os.statvfs(env.get_profile_path())
+ free_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL]
+ total_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BLOCKS]
+
+ fraction = (total_space - free_space) / float(total_space)
+ self._progress_bar.props.fraction = fraction
+ self._free_space_label.props.label = _('%(free_space)d MB Free') % \
+ {'free_space': free_space / (1024 * 1024)}
+
+class VolumePalette(Palette):
+ def __init__(self, mount):
+ Palette.__init__(self, label=mount.get_name())
+ self._mount = mount
+
+ self.props.secondary_text = mount.get_root().get_path()
+
+ vbox = gtk.VBox()
+ self.set_content(vbox)
+ vbox.show()
+
+ self._progress_bar = gtk.ProgressBar()
+ vbox.add(self._progress_bar)
+ self._progress_bar.show()
+
+ self._free_space_label = gtk.Label()
+ self._free_space_label.set_alignment(0.5, 0.5)
+ vbox.add(self._free_space_label)
+ self._free_space_label.show()
+
+ self.connect('popup', self.__popup_cb)
+
+ menu_item = MenuItem(_('Remove'))
+
+ icon = Icon(icon_name='media-eject', icon_size=gtk.ICON_SIZE_MENU)
+ menu_item.set_image(icon)
+ icon.show()
+
+ menu_item.connect('activate', self.__unmount_activate_cb)
+ self.menu.append(menu_item)
+ menu_item.show()
+
+ def __unmount_activate_cb(self, menu_item):
+ self._mount.unmount(self.__unmount_cb)
+
+ def __unmount_cb(self, mount, result):
+ logging.debug('__unmount_cb %r %r', mount, result)
+ mount.unmount_finish(result)
+
+ def __popup_cb(self, palette):
+ mount_point = self._mount.get_root().get_path()
+ stat = os.statvfs(mount_point)
+ free_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL]
+ total_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BLOCKS]
+
+ fraction = (total_space - free_space) / float(total_space)
+ self._progress_bar.props.fraction = fraction
+ self._free_space_label.props.label = _('%(free_space)d MB Free') % \
+ {'free_space': free_space / (1024 * 1024)}
+
diff --git a/shell/src/jarabe/view/pulsingicon.py b/shell/src/jarabe/view/pulsingicon.py
new file mode 100644
index 0000000..43ec358
--- /dev/null
+++ b/shell/src/jarabe/view/pulsingicon.py
@@ -0,0 +1,229 @@
+# Copyright (C) 2008 One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import math
+
+import gtk
+import gobject
+
+from sugar.graphics.icon import Icon, CanvasIcon
+
+_INTERVAL = 100
+_STEP = math.pi / 10 # must be a fraction of pi, for clean caching
+
+class Pulser(object):
+ def __init__(self, icon):
+ self._pulse_hid = None
+ self._icon = icon
+ self._level = 0
+ self._phase = 0
+
+ def start(self, restart=False):
+ if restart:
+ self._phase = 0
+ if self._pulse_hid is None:
+ self._pulse_hid = gobject.timeout_add(_INTERVAL, self.__pulse_cb)
+
+ def stop(self):
+ if self._pulse_hid is not None:
+ gobject.source_remove(self._pulse_hid)
+ self._pulse_hid = None
+ self._icon.xo_color = self._icon.get_base_color()
+
+ def update(self):
+ if self._icon.get_pulsing():
+ base_color = self._icon.get_base_color()
+ pulse_color = self._icon.get_pulse_color()
+
+ base_stroke = self._get_as_rgba(base_color.get_stroke_color())
+ pulse_stroke = self._get_as_rgba(pulse_color.get_stroke_color())
+ base_fill = self._get_as_rgba(base_color.get_fill_color())
+ pulse_fill = self._get_as_rgba(pulse_color.get_fill_color())
+
+ self._icon.set_stroke_color(
+ self._get_color_string(base_stroke, pulse_stroke))
+ self._icon.set_fill_color(
+ self._get_color_string(base_fill, pulse_fill))
+ else:
+ self._icon.xo_color = self._icon.base_color
+
+ def _get_as_rgba(self, html_color):
+ if html_color == 'none':
+ return 1.0, 1.0, 1.0
+ else:
+ color = gtk.gdk.color_parse(html_color)
+ return color.red / 65535.0, \
+ color.green / 65535.0, \
+ color.blue / 65535.0
+
+ def _get_color_string(self, orig_color, target_color):
+ r = orig_color[0] + self._level * (target_color[0] - orig_color[0])
+ g = orig_color[1] + self._level * (target_color[1] - orig_color[1])
+ b = orig_color[2] + self._level * (target_color[2] - orig_color[2])
+
+ return '#%02x%02x%02x' % (int(r * 255), int(g * 255), int(b * 255))
+
+ def __pulse_cb(self):
+ self._phase += _STEP
+ self._level = (math.sin(self._phase) + 1) / 2
+ self.update()
+
+ return True
+
+class PulsingIcon(Icon):
+ __gtype_name__ = 'SugarPulsingIcon'
+
+ def __init__(self, **kwargs):
+ self._pulser = Pulser(self)
+ self._base_color = None
+ self._pulse_color = None
+ self._paused = False
+ self._pulsing = False
+
+ Icon.__init__(self, **kwargs)
+
+ self._palette = None
+ self.connect('destroy', self.__destroy_cb)
+
+ def set_pulse_color(self, pulse_color):
+ self._pulse_color = pulse_color
+ self._pulser.update()
+
+ def get_pulse_color(self):
+ return self._pulse_color
+
+ pulse_color = gobject.property(
+ type=object, getter=get_pulse_color, setter=set_pulse_color)
+
+ def set_base_color(self, base_color):
+ self._base_color = base_color
+ self._pulser.update()
+
+ def get_base_color(self):
+ return self._base_color
+
+ base_color = gobject.property(
+ type=object, getter=get_base_color, setter=set_base_color)
+
+ def set_paused(self, paused):
+ self._paused = paused
+
+ if self._paused:
+ self._pulser.stop()
+ else:
+ self._pulser.start(restart=False)
+
+ def get_paused(self):
+ return self._paused
+
+ paused = gobject.property(
+ type=bool, default=False, getter=get_paused, setter=set_paused)
+
+ def set_pulsing(self, pulsing):
+ self._pulsing = pulsing
+
+ if self._pulsing:
+ self._pulser.start(restart=True)
+ else:
+ self._pulser.stop()
+
+ def get_pulsing(self):
+ return self._pulsing
+
+ pulsing = gobject.property(
+ type=bool, default=False, getter=get_pulsing, setter=set_pulsing)
+
+ def _get_palette(self):
+ return self._palette
+
+ def _set_palette(self, palette):
+ if self._palette is not None:
+ self._palette.props.invoker = None
+ self._palette = palette
+
+ palette = property(_get_palette, _set_palette)
+
+ def __destroy_cb(self, icon):
+ self._pulser.stop()
+ if self._palette is not None:
+ self._palette.destroy()
+
+class CanvasPulsingIcon(CanvasIcon):
+ __gtype_name__ = 'SugarCanvasPulsingIcon'
+
+ def __init__(self, **kwargs):
+ self._pulser = Pulser(self)
+ self._base_color = None
+ self._pulse_color = None
+ self._paused = False
+ self._pulsing = False
+
+ CanvasIcon.__init__(self, **kwargs)
+
+ self.connect('destroy', self.__destroy_cb)
+
+ def __destroy_cb(self, box):
+ self._pulser.stop()
+
+ def set_pulse_color(self, pulse_color):
+ self._pulse_color = pulse_color
+ self._pulser.update()
+
+ def get_pulse_color(self):
+ return self._pulse_color
+
+ pulse_color = gobject.property(
+ type=object, getter=get_pulse_color, setter=set_pulse_color)
+
+ def set_base_color(self, base_color):
+ self._base_color = base_color
+ self._pulser.update()
+
+ def get_base_color(self):
+ return self._base_color
+
+ base_color = gobject.property(
+ type=object, getter=get_base_color, setter=set_base_color)
+
+ def set_paused(self, paused):
+ self._paused = paused
+
+ if self._paused:
+ self._pulser.stop()
+ elif self._pulsing:
+ self._pulser.start(restart=False)
+
+ def get_paused(self):
+ return self._paused
+
+ paused = gobject.property(
+ type=bool, default=False, getter=get_paused, setter=set_paused)
+
+ def set_pulsing(self, pulsing):
+ self._pulsing = pulsing
+ if self._paused:
+ return
+
+ if self._pulsing:
+ self._pulser.start(restart=True)
+ else:
+ self._pulser.stop()
+
+ def get_pulsing(self):
+ return self._pulsing
+
+ pulsing = gobject.property(
+ type=bool, default=False, getter=get_pulsing, setter=set_pulsing)
diff --git a/shell/src/jarabe/view/service.py b/shell/src/jarabe/view/service.py
new file mode 100644
index 0000000..7af778a
--- /dev/null
+++ b/shell/src/jarabe/view/service.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""D-bus service providing access to the shell's functionality"""
+
+import dbus
+import gtk
+
+from jarabe.model import shell
+from jarabe.model import bundleregistry
+
+_DBUS_SERVICE = "org.laptop.Shell"
+_DBUS_SHELL_IFACE = "org.laptop.Shell"
+_DBUS_PATH = "/org/laptop/Shell"
+
+class UIService(dbus.service.Object):
+ """Provides d-bus service to script the shell's operations
+
+ Uses a shell_model object to observe events such as changes to:
+
+ * nickname
+ * colour
+ * icon
+ * currently active activity
+
+ and pass the event off to the methods in the dbus signature.
+
+ Key method here at the moment is add_bundle, which is used to
+ do a run-time registration of a bundle using it's application path.
+
+ XXX At the moment the d-bus service methods do not appear to do
+ anything other than add_bundle
+ """
+
+ def __init__(self):
+ bus = dbus.SessionBus()
+ bus_name = dbus.service.BusName(_DBUS_SERVICE, bus=bus)
+ dbus.service.Object.__init__(self, bus_name, _DBUS_PATH)
+
+ self._shell_model = shell.get_model()
+
+ @dbus.service.method(_DBUS_SHELL_IFACE,
+ in_signature="s", out_signature="s")
+ def GetBundlePath(self, bundle_id):
+ bundle = bundleregistry.get_registry().get_bundle(bundle_id)
+ if bundle:
+ return bundle.get_path()
+ else:
+ return ''
+
+ @dbus.service.method(_DBUS_SHELL_IFACE,
+ in_signature="s", out_signature="b")
+ def ActivateActivity(self, activity_id):
+ """Switch to the window related to this activity_id and return a boolean
+ indicating if there is a real (ie. not a launcher window) activity
+ already open.
+ """
+ activity = self._shell_model.get_activity_by_id(activity_id)
+
+ if activity is not None and activity.get_window() is not None:
+ activity.get_window().activate(gtk.get_current_event_time())
+ return self._shell_model.get_launcher(activity_id) is None
+
+ return False
+
+ @dbus.service.method(_DBUS_SHELL_IFACE,
+ in_signature="ss", out_signature="")
+ def NotifyLaunch(self, bundle_id, activity_id):
+ shell.get_model().notify_launch(activity_id, bundle_id)
+
+ @dbus.service.method(_DBUS_SHELL_IFACE,
+ in_signature="s", out_signature="")
+ def NotifyLaunchFailure(self, activity_id):
+ shell.get_model().notify_launch_failed(activity_id)
+
diff --git a/shell/src/jarabe/view/tabbinghandler.py b/shell/src/jarabe/view/tabbinghandler.py
new file mode 100644
index 0000000..f52bda3
--- /dev/null
+++ b/shell/src/jarabe/view/tabbinghandler.py
@@ -0,0 +1,148 @@
+# Copyright (C) 2008, Benjamin Berg <benjamin@sipsolutions.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import gobject
+import gtk
+
+from jarabe.model import shell
+
+_RAISE_DELAY = 250
+
+class TabbingHandler(object):
+ def __init__(self, frame, modifier):
+ self._frame = frame
+ self._tabbing = False
+ self._modifier = modifier
+ self._timeout = None
+
+ def _start_tabbing(self):
+ if not self._tabbing:
+ logging.debug('Grabing the input.')
+
+ screen = gtk.gdk.screen_get_default()
+ window = screen.get_root_window()
+ keyboard_grab_result = gtk.gdk.keyboard_grab(window)
+ pointer_grab_result = gtk.gdk.pointer_grab(window)
+
+ self._tabbing = (keyboard_grab_result == gtk.gdk.GRAB_SUCCESS and
+ pointer_grab_result == gtk.gdk.GRAB_SUCCESS)
+
+ # Now test that the modifier is still active to prevent race
+ # conditions. We also test if one of the grabs failed.
+ mask = window.get_pointer()[2]
+ if not self._tabbing or not (mask & self._modifier):
+ logging.debug('Releasing grabs again.')
+
+ # ungrab keyboard/pointer if the grab was successfull.
+ if keyboard_grab_result == gtk.gdk.GRAB_SUCCESS:
+ gtk.gdk.keyboard_ungrab()
+ if pointer_grab_result == gtk.gdk.GRAB_SUCCESS:
+ gtk.gdk.pointer_ungrab()
+
+ self._tabbing = False
+ else:
+ self._frame.show(self._frame.MODE_NON_INTERACTIVE)
+
+ def __timeout_cb(self, event_time):
+ self._activate_current(event_time)
+ self._timeout = None
+ return False
+
+ def _start_timeout(self, event_time):
+ self._cancel_timeout()
+ self._timeout = gobject.timeout_add(_RAISE_DELAY,
+ lambda: self.__timeout_cb(event_time))
+
+ def _cancel_timeout(self):
+ if self._timeout:
+ gobject.source_remove(self._timeout)
+ self._timeout = None
+
+ def _activate_current(self, event_time):
+ home_model = shell.get_model()
+ activity = home_model.get_tabbing_activity()
+ if activity and activity.get_window():
+ activity.get_window().activate(event_time)
+
+ def next_activity(self, event_time):
+ if not self._tabbing:
+ first_switch = True
+ self._start_tabbing()
+ else:
+ first_switch = False
+
+ if self._tabbing:
+ shell_model = shell.get_model()
+ zoom_level = shell_model.zoom_level
+ zoom_activity = (zoom_level == shell.ShellModel.ZOOM_ACTIVITY)
+
+ if not zoom_activity and first_switch:
+ activity = shell_model.get_active_activity()
+ else:
+ activity = shell_model.get_tabbing_activity()
+ activity = shell_model.get_next_activity(current=activity)
+
+ shell_model.set_tabbing_activity(activity)
+ self._start_timeout(event_time)
+ else:
+ self._activate_next_activity(event_time)
+
+ def previous_activity(self, event_time):
+ if not self._tabbing:
+ first_switch = True
+ self._start_tabbing()
+ else:
+ first_switch = False
+
+ if self._tabbing:
+ shell_model = shell.get_model()
+ zoom_level = shell_model.zoom_level
+ zoom_activity = (zoom_level == shell.ShellModel.ZOOM_ACTIVITY)
+
+ if not zoom_activity and first_switch:
+ activity = shell_model.get_active_activity()
+ else:
+ activity = shell_model.get_tabbing_activity()
+ activity = shell_model.get_previous_activity(current=activity)
+
+ shell_model.set_tabbing_activity(activity)
+ self._start_timeout(event_time)
+ else:
+ self._activate_next_activity(event_time)
+
+ def _activate_next_activity(self, event_time):
+ next_activity = shell.get_model().get_next_activity()
+ if next_activity:
+ next_activity.get_window().activate(event_time)
+
+ def stop(self, event_time):
+ gtk.gdk.keyboard_ungrab()
+ gtk.gdk.pointer_ungrab()
+ self._tabbing = False
+
+ self._frame.hide()
+
+ self._cancel_timeout()
+ self._activate_current(event_time)
+
+ home_model = shell.get_model()
+ home_model.set_tabbing_activity(None)
+
+ def is_tabbing(self):
+ return self._tabbing
+
diff --git a/shell/src/jarabe/view/viewsource.py b/shell/src/jarabe/view/viewsource.py
new file mode 100644
index 0000000..290df18
--- /dev/null
+++ b/shell/src/jarabe/view/viewsource.py
@@ -0,0 +1,464 @@
+# Copyright (C) 2008 One Laptop Per Child
+# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import logging
+import traceback
+from gettext import gettext as _
+
+import gobject
+import pango
+import gtk
+import gtksourceview2
+import dbus
+import gconf
+
+from sugar.graphics import style
+from sugar.graphics.icon import Icon
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.menuitem import MenuItem
+from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics.radiotoolbutton import RadioToolButton
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.datastore import datastore
+from sugar import mime
+
+_SOURCE_FONT = pango.FontDescription('Monospace %d' % style.FONT_SIZE)
+
+_logger = logging.getLogger('ViewSource')
+map_activity_to_window = {}
+
+def setup_view_source(activity):
+ service = activity.get_service()
+ if service is not None:
+ try:
+ service.HandleViewSource()
+ return
+ except dbus.DBusException, e:
+ expected_exceptions = ['org.freedesktop.DBus.Error.UnknownMethod',
+ 'org.freedesktop.DBus.Python.NotImplementedError']
+ if e.get_dbus_name() not in expected_exceptions:
+ logging.error(traceback.format_exc())
+ except Exception:
+ logging.error(traceback.format_exc())
+
+ window_xid = activity.get_xid()
+ if window_xid is None:
+ _logger.error('Activity without a window xid')
+ return
+
+ bundle_path = activity.get_bundle_path()
+
+ if window_xid in map_activity_to_window:
+ _logger.debug('Viewsource window already open for %s %s', window_xid,
+ bundle_path)
+ return
+
+ document_path = None
+ if service is not None:
+ try:
+ document_path = service.GetDocumentPath()
+ except dbus.DBusException, e:
+ expected_exceptions = ['org.freedesktop.DBus.Error.UnknownMethod',
+ 'org.freedesktop.DBus.Python.NotImplementedError']
+ if e.get_dbus_name() not in expected_exceptions:
+ logging.error(traceback.format_exc())
+ except Exception:
+ logging.error(traceback.format_exc())
+
+ if bundle_path is None and document_path is None:
+ _logger.debug('Activity without bundle_path nor document_path')
+ return
+
+ view_source = ViewSource(window_xid, bundle_path, document_path,
+ activity.get_title())
+ map_activity_to_window[window_xid] = view_source
+ view_source.show()
+
+class ViewSource(gtk.Window):
+ __gtype_name__ = 'SugarViewSource'
+
+ def __init__(self, window_xid, bundle_path, document_path, title):
+ gtk.Window.__init__(self)
+
+ logging.debug('ViewSource paths: %r %r', bundle_path, document_path)
+
+ self.set_decorated(False)
+ self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.set_border_width(style.LINE_WIDTH)
+
+ width = gtk.gdk.screen_width() - style.GRID_CELL_SIZE * 2
+ height = gtk.gdk.screen_height() - style.GRID_CELL_SIZE * 2
+ self.set_size_request(width, height)
+
+ self._parent_window_xid = window_xid
+
+ self.connect('realize', self.__realize_cb)
+ self.connect('destroy', self.__destroy_cb, document_path)
+ self.connect('key-press-event', self.__key_press_event_cb)
+
+ vbox = gtk.VBox()
+ self.add(vbox)
+ vbox.show()
+
+ toolbar = Toolbar(title, bundle_path, document_path)
+ vbox.pack_start(toolbar, expand=False)
+ toolbar.connect('stop-clicked', self.__stop_clicked_cb)
+ toolbar.connect('source-selected', self.__source_selected_cb)
+ toolbar.show()
+
+ pane = gtk.HPaned()
+ vbox.pack_start(pane)
+ pane.show()
+
+ self._selected_file = None
+ file_name = ''
+
+ activity_bundle = ActivityBundle(bundle_path)
+ command = activity_bundle.get_command()
+ if len(command.split(' ')) > 1:
+ name = command.split(' ')[1].split('.')[0]
+ file_name = name + '.py'
+ path = os.path.join(activity_bundle.get_path(), file_name)
+ self._selected_file = path
+
+ self._file_viewer = FileViewer(bundle_path, file_name)
+ self._file_viewer.connect('file-selected', self.__file_selected_cb)
+ pane.add1(self._file_viewer)
+ self._file_viewer.show()
+
+ self._source_display = SourceDisplay()
+ pane.add2(self._source_display)
+ self._source_display.show()
+ self._source_display.file_path = self._selected_file
+
+ if document_path is not None:
+ self._select_source(document_path)
+
+ def _calculate_char_width(self, char_count):
+ widget = gtk.Label('')
+ context = widget.get_pango_context()
+ pango_font = context.load_font(_SOURCE_FONT)
+ metrics = pango_font.get_metrics()
+ return pango.PIXELS(metrics.get_approximate_char_width()) * char_count
+
+ def __realize_cb(self, widget):
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+ self.window.set_accept_focus(True)
+
+ parent = gtk.gdk.window_foreign_new(self._parent_window_xid)
+ self.window.set_transient_for(parent)
+
+ def __stop_clicked_cb(self, widget):
+ self.destroy()
+
+ def __source_selected_cb(self, widget, path):
+ self._select_source(path)
+
+ def _select_source(self, path):
+ if os.path.isfile(path):
+ self._source_display.file_path = path
+ self._file_viewer.hide()
+ else:
+ self._file_viewer.set_path(path)
+ self._source_display.file_path = self._selected_file
+ self._file_viewer.show()
+
+ def __destroy_cb(self, window, document_path):
+ del map_activity_to_window[self._parent_window_xid]
+ if document_path is not None and os.path.exists(document_path):
+ os.unlink(document_path)
+
+ def __key_press_event_cb(self, window, event):
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == 'Escape':
+ self.destroy()
+
+ def __file_selected_cb(self, file_viewer, file_path):
+ if file_path is not None and os.path.isfile(file_path):
+ self._source_display.file_path = file_path
+ self._selected_file = file_path
+ else:
+ self._source_display.file_path = None
+
+class DocumentButton(RadioToolButton):
+ __gtype_name__ = 'SugarDocumentButton'
+
+ def __init__(self, file_name, document_path, title):
+ RadioToolButton.__init__(self)
+
+ self._document_path = document_path
+ self._title = title
+ self._jobject = None
+
+ self.props.tooltip = _('Instance Source')
+
+ client = gconf.client_get_default()
+ self._color = client.get_string('/desktop/sugar/user/color')
+ icon = Icon(file=file_name,
+ icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR,
+ xo_color=XoColor(self._color))
+ self.set_icon_widget(icon)
+ icon.show()
+
+ menu_item = MenuItem(_('Keep'))
+ icon = Icon(icon_name='document-save', icon_size=gtk.ICON_SIZE_MENU,
+ xo_color=XoColor(self._color))
+ menu_item.set_image(icon)
+
+ menu_item.connect('activate', self.__keep_in_journal_cb)
+ self.props.palette.menu.append(menu_item)
+ menu_item.show()
+
+ def __keep_in_journal_cb(self, menu_item):
+ mime_type = mime.get_from_file_name(self._document_path)
+ if mime_type == 'application/octet-stream':
+ mime_type = mime.get_for_file(self._document_path)
+
+ self._jobject = datastore.create()
+ title = _('Source') + ': ' + self._title
+ self._jobject.metadata['title'] = title
+ self._jobject.metadata['keep'] = '0'
+ self._jobject.metadata['buddies'] = ''
+ self._jobject.metadata['preview'] = ''
+ self._jobject.metadata['icon-color'] = self._color
+ self._jobject.metadata['mime_type'] = mime_type
+ self._jobject.metadata['source'] = '1'
+ self._jobject.file_path = self._document_path
+ datastore.write(self._jobject, transfer_ownership=True,
+ reply_handler=self.__internal_save_cb,
+ error_handler=self.__internal_save_error_cb)
+
+ def __internal_save_cb(self):
+ logging.debug("Saved Source object to datastore.")
+ self._jobject.destroy()
+
+ def __internal_save_error_cb(self, err):
+ logging.debug('Error saving Source object to datastore: %s', err)
+ self._jobject.destroy()
+
+class Toolbar(gtk.Toolbar):
+ __gtype_name__ = 'SugarViewSourceToolbar'
+
+ __gsignals__ = {
+ 'stop-clicked': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ 'source-selected': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ }
+
+ def __init__(self, title, bundle_path, document_path):
+ gtk.Toolbar.__init__(self)
+
+ document_button = None
+
+ self._add_separator()
+
+ activity_bundle = ActivityBundle(bundle_path)
+ file_name = activity_bundle.get_icon()
+
+ if document_path is not None and os.path.exists(document_path):
+ document_button = DocumentButton(file_name, document_path, title)
+ document_button.connect('toggled', self.__button_toggled_cb,
+ document_path)
+ self.insert(document_button, -1)
+ document_button.show()
+ self._add_separator()
+
+ if bundle_path is not None and os.path.exists(bundle_path):
+ activity_button = RadioToolButton()
+ icon = Icon(file=file_name,
+ icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR,
+ fill_color=style.COLOR_TRANSPARENT.get_svg(),
+ stroke_color=style.COLOR_WHITE.get_svg())
+ activity_button.set_icon_widget(icon)
+ icon.show()
+ if document_button is not None:
+ activity_button.props.group = document_button
+ activity_button.props.tooltip = _('Activity Bundle Source')
+ activity_button.connect('toggled', self.__button_toggled_cb,
+ bundle_path)
+ self.insert(activity_button, -1)
+ activity_button.show()
+ self._add_separator()
+
+ text = _('View source: %r') % title
+ label = gtk.Label()
+ label.set_markup('<b>%s</b>' % text)
+ label.set_alignment(0, 0.5)
+ self._add_widget(label)
+
+ self._add_separator(True)
+
+ stop = ToolButton(icon_name='dialog-cancel')
+ stop.set_tooltip(_('Close'))
+ stop.connect('clicked', self.__stop_clicked_cb)
+ self.insert(stop, -1)
+ stop.show()
+
+ def _add_separator(self, expand=False):
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ if expand:
+ separator.set_expand(True)
+ else:
+ separator.set_size_request(style.DEFAULT_SPACING, -1)
+ self.insert(separator, -1)
+ separator.show()
+
+ def _add_widget(self, widget, expand=False):
+ tool_item = gtk.ToolItem()
+ tool_item.set_expand(expand)
+
+ tool_item.add(widget)
+ widget.show()
+
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ def __stop_clicked_cb(self, button):
+ self.emit('stop-clicked')
+
+ def __button_toggled_cb(self, button, path):
+ if button.props.active:
+ self.emit('source-selected', path)
+
+class FileViewer(gtk.ScrolledWindow):
+ __gtype_name__ = 'SugarFileViewer'
+
+ __gsignals__ = {
+ 'file-selected': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([str])),
+ }
+
+ def __init__(self, path, initial_filename):
+ gtk.ScrolledWindow.__init__(self)
+
+ self.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
+ self.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
+ self.set_size_request(style.GRID_CELL_SIZE * 3, -1)
+
+ self._path = None
+ self._initial_filename = initial_filename
+
+ self._tree_view = gtk.TreeView()
+ self.add(self._tree_view)
+ self._tree_view.show()
+
+ self._tree_view.props.headers_visible = False
+ selection = self._tree_view.get_selection()
+ selection.connect('changed', self.__selection_changed_cb)
+
+ cell = gtk.CellRendererText()
+ column = gtk.TreeViewColumn()
+ column.pack_start(cell, True)
+ column.add_attribute(cell, 'text', 0)
+ self._tree_view.append_column(column)
+ self._tree_view.set_search_column(0)
+
+ self.set_path(path)
+
+ def set_path(self, path):
+ self.emit('file-selected', None)
+ if self._path == path:
+ return
+ self._path = path
+ self._tree_view.set_model(gtk.TreeStore(str, str))
+ self._add_dir_to_model(path)
+
+ def _add_dir_to_model(self, dir_path, parent=None):
+ model = self._tree_view.get_model()
+ for f in os.listdir(dir_path):
+ if not f.endswith('.pyc'):
+ full_path = os.path.join(dir_path, f)
+ if os.path.isdir(full_path):
+ new_iter = model.append(parent, [f, full_path])
+ self._add_dir_to_model(full_path, new_iter)
+ else:
+ current_iter = model.append(parent, [f, full_path])
+ if f == self._initial_filename:
+ selection = self._tree_view.get_selection()
+ selection.select_iter(current_iter)
+
+ def __selection_changed_cb(self, selection):
+ model, tree_iter = selection.get_selected()
+ if tree_iter is None:
+ file_path = None
+ else:
+ file_path = model.get_value(tree_iter, 1)
+ self.emit('file-selected', file_path)
+
+class SourceDisplay(gtk.ScrolledWindow):
+ __gtype_name__ = 'SugarSourceDisplay'
+
+ def __init__(self):
+ gtk.ScrolledWindow.__init__(self)
+
+ self.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
+ self.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
+
+ self._buffer = gtksourceview2.Buffer()
+ self._buffer.set_highlight_syntax(True)
+
+ self._source_view = gtksourceview2.View(self._buffer)
+ self._source_view.set_editable(False)
+ self._source_view.set_cursor_visible(True)
+ self._source_view.set_show_line_numbers(True)
+ self._source_view.set_show_right_margin(True)
+ self._source_view.set_right_margin_position(80)
+ #self._source_view.set_highlight_current_line(True) #FIXME: Ugly color
+ self._source_view.modify_font(_SOURCE_FONT)
+ self.add(self._source_view)
+ self._source_view.show()
+
+ self._file_path = None
+
+ def _set_file_path(self, file_path):
+ if file_path == self._file_path:
+ return
+ self._file_path = file_path
+
+ if self._file_path is None:
+ self._buffer.set_text('')
+ return
+
+ mime_type = mime.get_for_file(self._file_path)
+ logging.debug('Detected mime type: %r', mime_type)
+
+ language_manager = gtksourceview2.language_manager_get_default()
+ detected_language = None
+ for language_id in language_manager.get_language_ids():
+ language = language_manager.get_language(language_id)
+ if mime_type in language.get_mime_types():
+ detected_language = language
+ break
+
+ if detected_language is not None:
+ logging.debug('Detected language: %r',
+ detected_language.get_name())
+
+ self._buffer.set_language(detected_language)
+ self._buffer.set_text(open(self._file_path, 'r').read())
+
+ def _get_file_path(self):
+ return self._file_path
+
+ file_path = property(_get_file_path, _set_file_path)
+