From 7f5a0d8ab70a965b7e06f1262d42050b066d6265 Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Sun, 16 Sep 2007 01:24:08 +0000 Subject: [PATCH] Applied i18n patch from Marcos. --- deluge/i18n/POTFILES.in | 3 + deluge/i18n/deluge.pot | 521 ++++++++++++++++++++++++ deluge/plugins/queue/queue/gtkui.py | 24 +- deluge/ui/gtkui/glade/main_window.glade | 12 +- deluge/ui/gtkui/gtkui.py | 12 +- gettextize.sh | 2 + msgfmt.py | 438 ++++++++++++++++++++ setup.py | 64 ++- 8 files changed, 1055 insertions(+), 21 deletions(-) create mode 100644 deluge/i18n/POTFILES.in create mode 100644 deluge/i18n/deluge.pot create mode 100644 gettextize.sh create mode 100644 msgfmt.py diff --git a/deluge/i18n/POTFILES.in b/deluge/i18n/POTFILES.in new file mode 100644 index 000000000..0eff8a995 --- /dev/null +++ b/deluge/i18n/POTFILES.in @@ -0,0 +1,3 @@ +deluge/ui/gtkui/glade/main_window.glade +deluge/ui/gtkui/glade/preferences_dialog.glade +deluge/plugins/queue/queue/gtkui.py diff --git a/deluge/i18n/deluge.pot b/deluge/i18n/deluge.pot new file mode 100644 index 000000000..16b9fc2d0 --- /dev/null +++ b/deluge/i18n/deluge.pot @@ -0,0 +1,521 @@ +# 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 , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-15 18:22-0700\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: deluge/ui/gtkui/glade/main_window.glade:20 +msgid "_File" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:27 +msgid "_Add Torrent" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:42 +msgid "Add _URL" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:49 +msgid "_Clear Completed" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:69 +msgid "Quit & Shutdown Daemon" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:101 +msgid "_Edit" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:122 +msgid "_Torrent" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:129 +msgid "_View" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:137 +msgid "_Toolbar" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:145 +msgid "_Details" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:153 +msgid "Columns" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:164 +msgid "_Help" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:192 +msgid "Add torrent" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:193 +msgid "Add Torrent" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:205 +msgid "Remove the selected torrents" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:206 +msgid "Remove Torrent" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:218 +msgid "Remove the finished torrents" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:219 +msgid "Clear Finished" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:240 +msgid "Pause the selected torrents" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:241 +msgid "Pause" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:254 +msgid "Resume the selected torrents" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:255 +msgid "Resume" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:275 +#: deluge/ui/gtkui/glade/main_window.glade:276 +msgid "Preferences" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:420 +msgid "Name:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:439 +msgid "Next Announce:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:465 +msgid "Tracker Status:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:493 +msgid "Tracker:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:516 +msgid "Total Size:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:576 +msgid "# of files:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:595 +msgid "Torrent Info" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:666 +msgid "Availability:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:702 +msgid "Pieces:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:719 +msgid "ETA:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:740 +msgid "Peers:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:761 +#: deluge/ui/gtkui/glade/main_window.glade:782 +msgid "Speed:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:800 +msgid "Share Ratio:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:818 +msgid "Seeders:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:836 +msgid "Uploaded:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:854 +msgid "Downloaded:" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:966 +msgid "Statistics" +msgstr "" + +#: deluge/ui/gtkui/glade/main_window.glade:991 +msgid "Details" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:8 +msgid "Deluge Preferences" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:74 +msgid "Downloads" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:108 +msgid "Ask where to save each download" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:124 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:125 +msgid "Store all downloads in:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:142 +msgid "Select A Folder" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:161 +msgid "Download Location" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:197 +msgid "" +"Full allocation preallocates all of the space that is needed for the torrent " +"and prevents disk fragmentation" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:198 +msgid "Use Full Allocation" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:213 +msgid "Compact allocation only allocates space as needed" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:214 +msgid "Use Compact Allocation" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:232 +msgid "Allocation" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:266 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:267 +msgid "Enable selecting files for torrents before loading" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:280 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:281 +msgid "Prioritize first and last pieces of files in torrent" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:297 +msgid "Torrents" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:350 +msgid "Network" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:387 +msgid "From:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:414 +msgid "To:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:445 +msgid "Test Active Port" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:469 +msgid "Deluge will automatically choose a different port to use every time." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:470 +msgid "Use Random Ports" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:488 +msgid "Active Port:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:500 +msgid "0000" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:530 +msgid "Ports" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:562 +msgid "Distributed hash table may improve the amount of active connections." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:563 +msgid "Enable Mainline DHT" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:576 +msgid "DHT" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:609 +msgid "Universal Plug and Play" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:610 +msgid "UPnP" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:625 +msgid "NAT Port Mapping Protocol" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:626 +msgid "NAT-PMP" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:642 +msgid "µTorrent Peer-Exchange" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:643 +msgid "µTorrent-PeX" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:662 +msgid "Network Extras" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:698 +msgid "Inbound:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:707 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:731 +msgid "" +"Disabled\n" +"Enabled\n" +"Forced" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:721 +msgid "Outbound:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:750 +msgid "Level:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:759 +msgid "" +"Handshake\n" +"Either\n" +"Full Stream" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:778 +msgid "Prefer to encrypt the entire stream" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:795 +msgid "Encryption" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:849 +msgid "Bandwidth" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:887 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:911 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:977 +msgid "The maximum upload speed for all torrents. Set -1 for unlimited." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:889 +msgid "Maximum Upload Speed (KiB/s):" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:900 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:925 +msgid "The maximum number of connections allowed. Set -1 for unlimited." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:902 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1071 +msgid "Maximum Connections:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:913 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1058 +msgid "Maximum Upload Slots:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:943 +#: deluge/ui/gtkui/glade/preferences_dialog.glade:958 +msgid "The maximum download speed for all torrents. Set -1 for unlimited." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:945 +msgid "Maximum Download Speed (KiB/s):" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:996 +msgid "The maximum upload slots for all torrents. Set -1 for unlimited." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1018 +msgid "Global Bandwidth Usage" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1081 +msgid "The maximum number of connections per torrent. Set -1 for unlimited." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1097 +msgid "The maximum upload slots per torrent. Set -1 for unlimited." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1120 +msgid "Per Torrent Bandwidth Usage" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1174 +msgid "Other" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1208 +msgid "Enable system tray icon" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1223 +msgid "Minimize to tray on close" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1242 +msgid "Start in tray" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1263 +msgid "Password protect system tray" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1288 +msgid "Password:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1322 +msgid "System Tray" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1372 +msgid "" +"Auto-detect (xdg-open)\n" +"Konqueror\n" +"Nautilus\n" +"Thunar" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1396 +msgid "Custom:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1413 +msgid "Open folder with:" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1430 +msgid "Desktop File Manager" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1465 +msgid "" +"Deluge will check our servers and will tell you if a newer version has been " +"released" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1466 +msgid "Be alerted about new releases" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1483 +msgid "Updates" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1519 +msgid "" +"Help us improve Deluge by sending us your Python version, PyGTK version, OS " +"and processor types. Absolutely no other information is sent." +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1538 +msgid "Yes, please send anonymous statistics" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1557 +msgid "System Information" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1611 +msgid "Plugins" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1703 +msgid "gtk-cancel" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1715 +msgid "gtk-apply" +msgstr "" + +#: deluge/ui/gtkui/glade/preferences_dialog.glade:1730 +msgid "gtk-ok" +msgstr "" + +#: deluge/plugins/queue/queue/gtkui.py:100 +msgid "Queue Up" +msgstr "" + +#: deluge/plugins/queue/queue/gtkui.py:101 +msgid "Queue selected torrents up" +msgstr "" + +#: deluge/plugins/queue/queue/gtkui.py:105 +msgid "Queue Down" +msgstr "" + +#: deluge/plugins/queue/queue/gtkui.py:106 +msgid "Queue selected torrents down" +msgstr "" diff --git a/deluge/plugins/queue/queue/gtkui.py b/deluge/plugins/queue/queue/gtkui.py index f00d23331..f4db6a9f3 100644 --- a/deluge/plugins/queue/queue/gtkui.py +++ b/deluge/plugins/queue/queue/gtkui.py @@ -37,11 +37,25 @@ DBusGMainLoop(set_as_default=True) import pkg_resources import gtk.glade - +import gettext +import locale from deluge.log import LOG as log class GtkUI: def __init__(self, plugin_manager): + # Initialize gettext + locale.setlocale(locale.LC_MESSAGES, '') + locale.bindtextdomain("deluge", + pkg_resources.resource_filename( + "deluge", "i18n")) + locale.textdomain("deluge") + gettext.bindtextdomain("deluge", + pkg_resources.resource_filename( + "deluge", "i18n")) + gettext.textdomain("deluge") + gettext.install("deluge", + pkg_resources.resource_filename( + "deluge", "i18n")) log.debug("Queue GtkUI plugin initalized..") self.plugin = plugin_manager # Get a reference to the core portion of the plugin @@ -83,13 +97,13 @@ class GtkUI: # Add a toolbar buttons self.plugin.get_toolbar().add_separator() self.plugin.get_toolbar().add_toolbutton(stock="gtk-go-up", - label="Queue Up", - tooltip="Queue selected torrents up", + label=_("Queue Up"), + tooltip=_("Queue selected torrents up"), callback=self.on_toolbutton_queueup_clicked) self.plugin.get_toolbar().add_toolbutton(stock="gtk-go-down", - label="Queue Down", - tooltip="Queue selected torrents down", + label=_("Queue Down"), + tooltip=_("Queue selected torrents down"), callback=self.on_toolbutton_queuedown_clicked) # Add the queue menu to the torrent menu diff --git a/deluge/ui/gtkui/glade/main_window.glade b/deluge/ui/gtkui/glade/main_window.glade index 7e1190b9d..c0461fe09 100644 --- a/deluge/ui/gtkui/glade/main_window.glade +++ b/deluge/ui/gtkui/glade/main_window.glade @@ -190,7 +190,7 @@ True Add torrent - Add Torrent + Add Torrent True gtk-add @@ -203,7 +203,7 @@ True Remove the selected torrents - Remove Torrent + Remove Torrent True gtk-remove @@ -216,7 +216,7 @@ True Remove the finished torrents - Clear Finished + Clear Finished True gtk-clear @@ -238,7 +238,7 @@ True Pause the selected torrents - Pause + Pause True gtk-media-pause @@ -252,7 +252,7 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK Resume the selected torrents - Resume + Resume gtk-media-play @@ -273,7 +273,7 @@ True Preferences - Preferences + Preferences True gtk-preferences diff --git a/deluge/ui/gtkui/gtkui.py b/deluge/ui/gtkui/gtkui.py index a14918f2d..9a859b753 100644 --- a/deluge/ui/gtkui/gtkui.py +++ b/deluge/ui/gtkui/gtkui.py @@ -35,6 +35,7 @@ import pygtk pygtk.require('2.0') import gtk, gtk.glade import gettext +import locale import pkg_resources from mainwindow import MainWindow @@ -46,15 +47,18 @@ from deluge.log import LOG as log class GtkUI: def __init__(self): # Initialize gettext + locale.setlocale(locale.LC_MESSAGES, '') + locale.bindtextdomain("deluge", + pkg_resources.resource_filename( + "deluge", "i18n")) + locale.textdomain("deluge") gettext.bindtextdomain("deluge", pkg_resources.resource_filename( - "deluge.ui.gtkui", - "po")) + "deluge", "i18n")) gettext.textdomain("deluge") gettext.install("deluge", pkg_resources.resource_filename( - "deluge.ui.gtkui", - "po")) + "deluge", "i18n")) # Initialize the main window self.mainwindow = MainWindow() diff --git a/gettextize.sh b/gettextize.sh new file mode 100644 index 000000000..281903741 --- /dev/null +++ b/gettextize.sh @@ -0,0 +1,2 @@ +#!/bin/sh +xgettext -f deluge/i18n/POTFILES.in -o deluge/i18n/deluge.pot diff --git a/msgfmt.py b/msgfmt.py new file mode 100644 index 000000000..31d117d9c --- /dev/null +++ b/msgfmt.py @@ -0,0 +1,438 @@ +# -*- coding: iso-8859-1 -*- +# Written by Martin v. Lwis +# Plural forms support added by alexander smishlajev +""" +Generate binary message catalog from textual translation description. + +This program converts a textual Uniforum-style message catalog (.po file) into +a binary GNU catalog (.mo file). This is essentially the same function as the +GNU msgfmt program, however, it is a simpler implementation. + +Usage: msgfmt.py [OPTIONS] filename.po + +Options: + -o file + --output-file=file + Specify the output file to write to. If omitted, output will go to a + file named filename.mo (based off the input file name). + + -h + --help + Print this message and exit. + + -V + --version + Display version information and exit. +""" + +import sys +import os +import getopt +import struct +import array + +__version__ = "1.1" + +MESSAGES = {} + + +def usage (ecode, msg=''): + """ + Print usage and msg and exit with given code. + """ + print >> sys.stderr, __doc__ + if msg: + print >> sys.stderr, msg + sys.exit(ecode) + + +def add (msgid, transtr, fuzzy): + """ + Add a non-fuzzy translation to the dictionary. + """ + global MESSAGES + if not fuzzy and transtr and not transtr.startswith('\0'): + MESSAGES[msgid] = transtr + + +def generate (): + """ + Return the generated output. + """ + global MESSAGES + keys = MESSAGES.keys() + # the keys are sorted in the .mo file + keys.sort() + offsets = [] + ids = strs = '' + for _id in keys: + # For each string, we need size and file offset. Each string is NUL + # terminated; the NUL does not count into the size. + offsets.append((len(ids), len(_id), len(strs), len(MESSAGES[_id]))) + ids += _id + '\0' + strs += MESSAGES[_id] + '\0' + output = '' + # The header is 7 32-bit unsigned integers. We don't use hash tables, so + # the keys start right after the index tables. + # translated string. + keystart = 7*4+16*len(keys) + # and the values start after the keys + valuestart = keystart + len(ids) + koffsets = [] + voffsets = [] + # The string table first has the list of keys, then the list of values. + # Each entry has first the size of the string, then the file offset. + for o1, l1, o2, l2 in offsets: + koffsets += [l1, o1+keystart] + voffsets += [l2, o2+valuestart] + offsets = koffsets + voffsets + output = struct.pack("Iiiiiii", + 0x950412deL, # Magic + 0, # Version + len(keys), # # of entries + 7*4, # start of key index + 7*4+len(keys)*8, # start of value index + 0, 0) # size and offset of hash table + output += array.array("i", offsets).tostring() + output += ids + output += strs + return output + + +def make (filename, outfile): + ID = 1 + STR = 2 + global MESSAGES + MESSAGES = {} + + # Compute .mo name from .po name and arguments + if filename.endswith('.po'): + infile = filename + else: + infile = filename + '.po' + if outfile is None: + outfile = os.path.splitext(infile)[0] + '.mo' + + try: + lines = open(infile).readlines() + except IOError, msg: + print >> sys.stderr, msg + sys.exit(1) + + section = None + fuzzy = 0 + + # Parse the catalog + msgid = msgstr = '' + lno = 0 + for l in lines: + lno += 1 + # If we get a comment line after a msgstr, this is a new entry + if l[0] == '#' and section == STR: + add(msgid, msgstr, fuzzy) + section = None + fuzzy = 0 + # Record a fuzzy mark + if l[:2] == '#,' and (l.find('fuzzy') >= 0): + fuzzy = 1 + # Skip comments + if l[0] == '#': + continue + # Start of msgid_plural section, separate from singular form with \0 + if l.startswith('msgid_plural'): + msgid += '\0' + l = l[12:] + # Now we are in a msgid section, output previous section + elif l.startswith('msgid'): + if section == STR: + add(msgid, msgstr, fuzzy) + section = ID + l = l[5:] + msgid = msgstr = '' + # Now we are in a msgstr section + elif l.startswith('msgstr'): + section = STR + l = l[6:] + # Check for plural forms + if l.startswith('['): + # Separate plural forms with \0 + if not l.startswith('[0]'): + msgstr += '\0' + # Ignore the index - must come in sequence + l = l[l.index(']') + 1:] + # Skip empty lines + l = l.strip() + if not l: + continue + # XXX: Does this always follow Python escape semantics? + l = eval(l) + if section == ID: + msgid += l + elif section == STR: + msgstr += l + else: + print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \ + 'before:' + print >> sys.stderr, l + sys.exit(1) + # Add last entry + if section == STR: + add(msgid, msgstr, fuzzy) + + # Compute output + output = generate() + + try: + open(outfile,"wb").write(output) + except IOError,msg: + print >> sys.stderr, msg + + +def main (): + try: + opts, args = getopt.getopt(sys.argv[1:], 'hVo:', + ['help', 'version', 'output-file=']) + except getopt.error, msg: + usage(1, msg) + + outfile = None + # parse options + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-V', '--version'): + print >> sys.stderr, "msgfmt.py", __version__ + sys.exit(0) + elif opt in ('-o', '--output-file'): + outfile = arg + # do it + if not args: + print >> sys.stderr, 'No input file given' + print >> sys.stderr, "Try `msgfmt --help' for more information." + return + + for filename in args: + make(filename, outfile) + + +if __name__ == '__main__': + main() +# -*- coding: iso-8859-1 -*- +# Written by Martin v. Lwis +# Plural forms support added by alexander smishlajev +""" +Generate binary message catalog from textual translation description. + +This program converts a textual Uniforum-style message catalog (.po file) into +a binary GNU catalog (.mo file). This is essentially the same function as the +GNU msgfmt program, however, it is a simpler implementation. + +Usage: msgfmt.py [OPTIONS] filename.po + +Options: + -o file + --output-file=file + Specify the output file to write to. If omitted, output will go to a + file named filename.mo (based off the input file name). + + -h + --help + Print this message and exit. + + -V + --version + Display version information and exit. +""" + +import sys +import os +import getopt +import struct +import array + +__version__ = "1.1" + +MESSAGES = {} + + +def usage (ecode, msg=''): + """ + Print usage and msg and exit with given code. + """ + print >> sys.stderr, __doc__ + if msg: + print >> sys.stderr, msg + sys.exit(ecode) + + +def add (msgid, transtr, fuzzy): + """ + Add a non-fuzzy translation to the dictionary. + """ + global MESSAGES + if not fuzzy and transtr and not transtr.startswith('\0'): + MESSAGES[msgid] = transtr + + +def generate (): + """ + Return the generated output. + """ + global MESSAGES + keys = MESSAGES.keys() + # the keys are sorted in the .mo file + keys.sort() + offsets = [] + ids = strs = '' + for _id in keys: + # For each string, we need size and file offset. Each string is NUL + # terminated; the NUL does not count into the size. + offsets.append((len(ids), len(_id), len(strs), len(MESSAGES[_id]))) + ids += _id + '\0' + strs += MESSAGES[_id] + '\0' + output = '' + # The header is 7 32-bit unsigned integers. We don't use hash tables, so + # the keys start right after the index tables. + # translated string. + keystart = 7*4+16*len(keys) + # and the values start after the keys + valuestart = keystart + len(ids) + koffsets = [] + voffsets = [] + # The string table first has the list of keys, then the list of values. + # Each entry has first the size of the string, then the file offset. + for o1, l1, o2, l2 in offsets: + koffsets += [l1, o1+keystart] + voffsets += [l2, o2+valuestart] + offsets = koffsets + voffsets + output = struct.pack("Iiiiiii", + 0x950412deL, # Magic + 0, # Version + len(keys), # # of entries + 7*4, # start of key index + 7*4+len(keys)*8, # start of value index + 0, 0) # size and offset of hash table + output += array.array("i", offsets).tostring() + output += ids + output += strs + return output + + +def make (filename, outfile): + ID = 1 + STR = 2 + global MESSAGES + MESSAGES = {} + + # Compute .mo name from .po name and arguments + if filename.endswith('.po'): + infile = filename + else: + infile = filename + '.po' + if outfile is None: + outfile = os.path.splitext(infile)[0] + '.mo' + + try: + lines = open(infile).readlines() + except IOError, msg: + print >> sys.stderr, msg + sys.exit(1) + + section = None + fuzzy = 0 + + # Parse the catalog + msgid = msgstr = '' + lno = 0 + for l in lines: + lno += 1 + # If we get a comment line after a msgstr, this is a new entry + if l[0] == '#' and section == STR: + add(msgid, msgstr, fuzzy) + section = None + fuzzy = 0 + # Record a fuzzy mark + if l[:2] == '#,' and (l.find('fuzzy') >= 0): + fuzzy = 1 + # Skip comments + if l[0] == '#': + continue + # Start of msgid_plural section, separate from singular form with \0 + if l.startswith('msgid_plural'): + msgid += '\0' + l = l[12:] + # Now we are in a msgid section, output previous section + elif l.startswith('msgid'): + if section == STR: + add(msgid, msgstr, fuzzy) + section = ID + l = l[5:] + msgid = msgstr = '' + # Now we are in a msgstr section + elif l.startswith('msgstr'): + section = STR + l = l[6:] + # Check for plural forms + if l.startswith('['): + # Separate plural forms with \0 + if not l.startswith('[0]'): + msgstr += '\0' + # Ignore the index - must come in sequence + l = l[l.index(']') + 1:] + # Skip empty lines + l = l.strip() + if not l: + continue + # XXX: Does this always follow Python escape semantics? + l = eval(l) + if section == ID: + msgid += l + elif section == STR: + msgstr += l + else: + print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \ + 'before:' + print >> sys.stderr, l + sys.exit(1) + # Add last entry + if section == STR: + add(msgid, msgstr, fuzzy) + + # Compute output + output = generate() + + try: + open(outfile,"wb").write(output) + except IOError,msg: + print >> sys.stderr, msg + + +def main (): + try: + opts, args = getopt.getopt(sys.argv[1:], 'hVo:', + ['help', 'version', 'output-file=']) + except getopt.error, msg: + usage(1, msg) + + outfile = None + # parse options + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-V', '--version'): + print >> sys.stderr, "msgfmt.py", __version__ + sys.exit(0) + elif opt in ('-o', '--output-file'): + outfile = arg + # do it + if not args: + print >> sys.stderr, 'No input file given' + print >> sys.stderr, "Try `msgfmt --help' for more information." + return + + for filename in args: + make(filename, outfile) + + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index ba5c4bdce..950c8d4be 100644 --- a/setup.py +++ b/setup.py @@ -32,6 +32,12 @@ import ez_setup ez_setup.use_setuptools() from setuptools import setup, find_packages, Extension +from distutils import cmd +from distutils.command.build import build as _build +from distutils.command.install import install as _install +from distutils.command.install_data import install_data as _install_data +import msgfmt + import platform import glob import os @@ -84,6 +90,52 @@ libtorrent = Extension( sources = _sources ) +class build_trans(cmd.Command): + description = 'Compile .po files into .mo files' + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + po_dir = os.path.join(os.path.dirname(__file__), 'deluge/i18n/') + for path, names, filenames in os.walk(po_dir): + for f in filenames: + if f.endswith('.po'): + lang = f[:len(f) - 3] + src = os.path.join(path, f) + dest_path = os.path.join('deluge', 'i18n', lang, \ + 'LC_MESSAGES') + dest = os.path.join(dest_path, 'deluge.mo') + if not os.path.exists(dest_path): + os.makedirs(dest_path) + if not os.path.exists(dest): + print 'Compiling %s' % src + msgfmt.make(src, dest) + else: + src_mtime = os.stat(src)[8] + dest_mtime = os.stat(dest)[8] + if src_mtime > dest_mtime: + print 'Compiling %s' % src + msgfmt.make(src, dest) + +class build(_build): + sub_commands = _build.sub_commands + [('build_trans', None)] + def run(self): + _build.run(self) + +class install_data(_install_data): + def run(self): + _install_data.run(self) + +cmdclass = { + 'build': build, + 'build_trans': build_trans, + 'install_data': install_data +} + # Build the plugin eggs for path in glob.glob('deluge/plugins/*'): print path + "/setup.py" @@ -95,23 +147,23 @@ setup( name = "deluge", fullname = "Deluge Bittorent Client", version = "0.6.0.0", - author = "Andrew Resch", - author_email = "andrewresch@gmail.com", + author = "Andrew Resch, Marcos Pinto", + author_email = "andrewresch@gmail.com, markybob@dipconsultants.com", description = "GTK+ bittorrent client", url = "http://deluge-torrent.org", license = "GPLv2", - include_package_data = True, package_data = {"deluge": ["ui/gtkui/glade/*.glade", "data/pixmaps/*.png", - "ui/gtkui/po/*.po?", "plugins/*.egg", + "i18n/*.pot", + "i18n/*/LC_MESSAGES/*.mo" ]}, ext_package = "deluge", ext_modules = [libtorrent], packages = find_packages(exclude=["plugins"]), + cmdclass=cmdclass, entry_points = """ [console_scripts] deluge = deluge.main:main - """ -) + """)