mirror of
https://github.com/Hopiu/linkchecker.git
synced 2026-04-28 01:54:42 +00:00
i18n
git-svn-id: https://linkchecker.svn.sourceforge.net/svnroot/linkchecker/trunk/linkchecker@78 e7d03fd6-7b0d-0410-9947-9c21f3af8025
This commit is contained in:
parent
6f375c936c
commit
378b99625e
7 changed files with 292 additions and 39 deletions
|
|
@ -1,10 +1,10 @@
|
|||
build-stamp
|
||||
.files-stamp
|
||||
test.prof
|
||||
sample.html
|
||||
*-out.*
|
||||
*.so
|
||||
*.o
|
||||
*.mo
|
||||
build
|
||||
linkchecker-*.tar.gz
|
||||
MANIFEST
|
||||
|
|
|
|||
8
Makefile
8
Makefile
|
|
@ -19,9 +19,11 @@ clean:
|
|||
rm -rf $(ALLPACKAGES) $(PACKAGE)-out.*
|
||||
|
||||
install:
|
||||
./setup.py install --prefix=/tmp/usr
|
||||
# do what I mean, Distutils!
|
||||
cp -a /tmp/usr/* $(DESTDIR)/usr
|
||||
# ha! the root option finally made it into distutils
|
||||
./setup.py install --root=$(DESTDIR)
|
||||
# german translation mit Rezepten von Zlatko :)
|
||||
msgfmt -o linkcheck.mo linkcheck/messages.po
|
||||
install -c -m 644 linkcheck.mo $(DESTDIR)/usr/share/locale/de/LC_MESSAGES/
|
||||
# remove following line if Distutils have script support
|
||||
#install -c -m 755 linkchecker $(DESTDIR)/usr/bin/
|
||||
install -c -m 644 linkcheckerrc $(DESTDIR)/etc/
|
||||
|
|
|
|||
1
debian/dirs
vendored
1
debian/dirs
vendored
|
|
@ -3,3 +3,4 @@ usr/lib/python1.5/site-packages/linkcheck
|
|||
usr/bin
|
||||
etc
|
||||
usr/share/doc/linkchecker
|
||||
usr/share/locale/de/LC_MESSAGES
|
||||
|
|
|
|||
209
fintl.py
Normal file
209
fintl.py
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
#!/usr/bin/env python
|
||||
## vim:ts=4:et:nowrap
|
||||
"""i18n (multiple language) support. Reads .mo files from GNU gettext msgfmt
|
||||
|
||||
If you want to prepare your Python programs for i18n you could simply
|
||||
add the following lines to the top of a BASIC_MAIN module of your py-program:
|
||||
try:
|
||||
import fintl
|
||||
gettext = fintl.gettext
|
||||
fintl.bindtextdomain(YOUR_PROGRAM, YOUR_LOCALEDIR)
|
||||
fintl.textdomain(YOUR_PROGRAM)
|
||||
except ImportError:
|
||||
def gettext(msg):
|
||||
return msg
|
||||
_ = gettext
|
||||
and/or also add the following to the top of any module containing messages:
|
||||
import BASIC_MAIN
|
||||
_ = BASIC_MAIN.gettext
|
||||
|
||||
Now you could use _("....") everywhere instead of "...." for message texts.
|
||||
|
||||
Once you have written your internationalized program, you can use
|
||||
the suite of utility programs contained in the GNU gettext package to aid
|
||||
the translation into other languages.
|
||||
|
||||
You ARE NOT REQUIRED to release the sourcecode of your program, since
|
||||
linking of your program against GPL code is avoided by this module.
|
||||
Although it is possible to use the GNU gettext library by using the
|
||||
*intl.so* module written by Martin von L÷wis if this is available. But it is
|
||||
not required to use it in the first place.
|
||||
"""
|
||||
# Copyright 1999 by <mailto: pf@artcom-gmbh.de> (Peter Funk)
|
||||
#
|
||||
# All Rights Reserved
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose and without fee is hereby granted,
|
||||
# provided that the above copyright notice appear in all copies.
|
||||
|
||||
# ArtCom GmbH AND Peter Funk DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS, IN NO EVENT SHALL ArtCom GmBH or Peter Funk BE LIABLE
|
||||
# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
_default_localedir = '/usr/share/locale'
|
||||
_default_domain = 'python'
|
||||
|
||||
# check out, if Martin v. L÷wis 'intl' module interface to the GNU gettext
|
||||
# library is available and use it only, if it is available:
|
||||
try:
|
||||
from intl import *
|
||||
except ImportError:
|
||||
# now do what the gettext library provides in pure Python:
|
||||
error = 'fintl.error'
|
||||
# some globals preserving state:
|
||||
_languages = []
|
||||
_default_mo = None # This is default message outfile used by 'gettext'
|
||||
_loaded_mos = {} # This is a dictionary of loaded message output files
|
||||
|
||||
# some small little helper routines:
|
||||
def _check_env():
|
||||
"""examine language enviroment variables and return list of languages"""
|
||||
# TODO: This should somehow try to find out locale information on
|
||||
# Non-unix platforms like WinXX and MacOS. Suggestions welcome!
|
||||
languages = []
|
||||
import os, string
|
||||
for envvar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
|
||||
if os.environ.has_key(envvar):
|
||||
languages = string.split(os.environ[envvar], ':')
|
||||
break
|
||||
# use locale 'C' as default fallback:
|
||||
if 'C' not in _languages:
|
||||
languages.append('C')
|
||||
return languages
|
||||
|
||||
# Utility function used to decode binary .mo file header and seek tables:
|
||||
def _decode_Word(bin):
|
||||
# This assumes little endian (intel, vax) byte order.
|
||||
return ord(bin[0]) + (ord(bin[1]) << 8) + \
|
||||
(ord(bin[2]) << 16) + (ord(bin[3]) << 24)
|
||||
|
||||
# Now the methods designed to be used from outside:
|
||||
|
||||
def gettext(message):
|
||||
"""return localized version of a 'message' string"""
|
||||
if _default_mo is None:
|
||||
textdomain()
|
||||
return _default_mo.gettext(message)
|
||||
|
||||
_ = gettext
|
||||
|
||||
def dgettext(domain, message):
|
||||
"""like gettext but looks up 'message' in a special 'domain'"""
|
||||
# This may useful for larger software systems
|
||||
if not _loaded_mos.has_key(domain):
|
||||
raise error, "No '" + domain + "' message domain"
|
||||
return _loaded_mos[domain].gettext(message)
|
||||
|
||||
class _MoDict:
|
||||
"""read a .mo file into a python dictionary"""
|
||||
__MO_MAGIC = 0x950412de # Magic number of .mo files
|
||||
def __init__(self, domain=_default_domain, localedir=_default_localedir):
|
||||
global _languages
|
||||
self.catalog = {}
|
||||
self.domain = domain
|
||||
self.localedir = localedir
|
||||
# delayed access to environment variables:
|
||||
if not _languages:
|
||||
_languages = _check_env()
|
||||
for self.lang in _languages:
|
||||
if self.lang == 'C':
|
||||
return
|
||||
mo_filename = "%s//%s/LC_MESSAGES/%s.mo" % (
|
||||
localedir, self.lang, domain)
|
||||
try:
|
||||
buffer = open(mo_filename, "rb").read()
|
||||
break
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
return # assume C locale
|
||||
# Decode the header of the .mo file (5 little endian 32 bit words):
|
||||
if _decode_Word(buffer[:4]) != self.__MO_MAGIC :
|
||||
raise error, '%s seems not be a valid .mo file' % mo_filename
|
||||
self.mo_version = _decode_Word(buffer[4:8])
|
||||
num_messages = _decode_Word(buffer[8:12])
|
||||
master_index = _decode_Word(buffer[12:16])
|
||||
transl_index = _decode_Word(buffer[16:20])
|
||||
buf_len = len(buffer)
|
||||
# now put all messages from the .mo file buffer in the catalog dict:
|
||||
for i in xrange(0, num_messages):
|
||||
start_master= _decode_Word(buffer[master_index+4:master_index+8])
|
||||
end_master = start_master + \
|
||||
_decode_Word(buffer[master_index:master_index+4])
|
||||
start_transl= _decode_Word(buffer[transl_index+4:transl_index+8])
|
||||
end_transl = start_transl + \
|
||||
_decode_Word(buffer[transl_index:transl_index+4])
|
||||
if end_master <= buf_len and end_transl <= buf_len:
|
||||
self.catalog[buffer[start_master:end_master]]=\
|
||||
buffer[start_transl:end_transl]
|
||||
else:
|
||||
raise error, ".mo file '%s' is corrupt" % mo_filename
|
||||
# advance to the next entry in seek tables:
|
||||
master_index= master_index + 8
|
||||
transl_index= transl_index + 8
|
||||
|
||||
def gettext(self, message):
|
||||
"""return the translation of a given message"""
|
||||
try:
|
||||
return self.catalog[message]
|
||||
except KeyError:
|
||||
return message
|
||||
# _MoDict instances may be also accessed using mo[msg] or mo(msg):
|
||||
__getitem = gettext
|
||||
__call__ = gettext
|
||||
|
||||
def textdomain(domain=_default_domain):
|
||||
"""Sets the 'domain' to be used by this program. Defaults to 'python'"""
|
||||
global _default_mo
|
||||
if not _loaded_mos.has_key(domain):
|
||||
_loaded_mos[domain] = _MoDict(domain)
|
||||
_default_mo = _loaded_mos[domain]
|
||||
|
||||
def bindtextdomain(domain, localedir=_default_localedir):
|
||||
global _default_mo
|
||||
if not _loaded_mos.has_key(domain):
|
||||
_loaded_mos[domain] = _MoDict(domain, localedir)
|
||||
if _default_mo is not None:
|
||||
_default_mo = _loaded_mos[domain]
|
||||
|
||||
def translator(domain=_default_domain, localedir=_default_localedir):
|
||||
"""returns a gettext compatible function object
|
||||
|
||||
which is bound to the domain given as parameter"""
|
||||
pass # TODO implement this
|
||||
|
||||
def _testdriver(argv):
|
||||
message = ""
|
||||
domain = _default_domain
|
||||
localedir = _default_localedir
|
||||
if len(argv) > 1:
|
||||
message = argv[1]
|
||||
if len(argv) > 2:
|
||||
domain = argv[2]
|
||||
if len(argv) > 3:
|
||||
localedir = argv[3]
|
||||
# now perform some testing of this module:
|
||||
bindtextdomain(domain, localedir)
|
||||
textdomain(domain)
|
||||
info = gettext('') # this is where special info is often stored
|
||||
if info:
|
||||
print ".mo file for domain %s in %s contains:" % (domain, localedir)
|
||||
print info
|
||||
else:
|
||||
print ".mo file contains no info"
|
||||
if message:
|
||||
print "Translation of '"+ message+ "' is '"+ _(message)+ "'"
|
||||
else:
|
||||
for msg in ("Cancel", "No", "OK", "Quit", "Yes"):
|
||||
print "Translation of '"+ msg + "' is '"+ _(msg)+ "'"
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "-?"):
|
||||
print "Usage :", sys.argv[0], "[ MESSAGE [ DOMAIN [ LOCALEDIR ]]]"
|
||||
_testdriver(sys.argv)
|
||||
|
|
@ -13,7 +13,9 @@ newUrl(self,urlData)
|
|||
endOfOutput(self)
|
||||
Called at the end of checking to close filehandles and such.
|
||||
"""
|
||||
import sys,time,Config,StringUtil
|
||||
import sys,time
|
||||
import Config,StringUtil,linkcheck
|
||||
_ = linkcheck.gettext
|
||||
|
||||
# ANSI color codes
|
||||
ESC="\x1b"
|
||||
|
|
@ -38,6 +40,20 @@ TableError="<td bgcolor=\"db4930\">"
|
|||
TableOK="<td bgcolor=\"3ba557\">"
|
||||
RowEnd="</td></tr>\n"
|
||||
MyFont="<font face=\"Lucida,Verdana,Arial,sans-serif,Helvetica\">"
|
||||
KeyWords = ["Real URL",
|
||||
"Result",
|
||||
"Base",
|
||||
"Parent URL",
|
||||
"Info",
|
||||
"Warning",
|
||||
"D/L Time",
|
||||
"Check Time",
|
||||
]
|
||||
MaxIndent = max(map(len, KeyWords))+1
|
||||
Spaces = {}
|
||||
for key in KeyWords:
|
||||
Spaces[key] = " "*(MaxIndent - len(key))
|
||||
|
||||
|
||||
# return formatted time
|
||||
def _strtime(t):
|
||||
|
|
@ -50,16 +66,6 @@ class StandardLogger:
|
|||
blank lines.
|
||||
A URL log consists of two or more lines. Each line consists of
|
||||
keyword and data, separated by whitespace.
|
||||
Keywords:
|
||||
Real URL (necessary)
|
||||
Result (necessary)
|
||||
Base
|
||||
Parent URL
|
||||
Info
|
||||
Warning
|
||||
D/L Time
|
||||
Check Time
|
||||
|
||||
Unknown keywords will be ignored.
|
||||
"""
|
||||
|
||||
|
|
@ -73,38 +79,45 @@ class StandardLogger:
|
|||
self.starttime = time.time()
|
||||
self.fd.write(Config.AppInfo+"\n"+
|
||||
Config.Freeware+"\n"+
|
||||
"Get the newest version at "+Config.Url+"\n"+
|
||||
"Write comments and bugs to "+Config.Email+"\n\n"+
|
||||
"Start checking at "+_strtime(self.starttime)+"\n")
|
||||
_("Get the newest version at ")+Config.Url+"\n"+
|
||||
_("Write comments and bugs to ")+Config.Email+"\n\n"+
|
||||
_("Start checking at ")+_strtime(self.starttime)+"\n")
|
||||
self.fd.flush()
|
||||
|
||||
|
||||
def newUrl(self, urldata):
|
||||
self.fd.write("\nURL "+urldata.urlName)
|
||||
self.fd.write("\n"+_("URL")+Spaces["URL"]+urldata.urlName)
|
||||
if urldata.cached:
|
||||
self.fd.write(" (cached)\n")
|
||||
else:
|
||||
self.fd.write("\n")
|
||||
if urldata.parentName:
|
||||
self.fd.write("Parent URL "+urldata.parentName+", line "+
|
||||
self.fd.write(_("Parent URL")+Spaces["Parent URL"]+
|
||||
urldata.parentName+_(", line ")+
|
||||
str(urldata.line)+"\n")
|
||||
if urldata.baseRef:
|
||||
self.fd.write("Base "+urldata.baseRef+"\n")
|
||||
self.fd.write(_("Base")+Spaces["Base"]+urldata.baseRef+"\n")
|
||||
if urldata.url:
|
||||
self.fd.write("Real URL "+urldata.url+"\n")
|
||||
self.fd.write(_("Real URL")+Spaces["Real URL"]+urldata.url+"\n")
|
||||
if urldata.downloadtime:
|
||||
self.fd.write("D/L Time %.3f seconds\n" % urldata.downloadtime)
|
||||
self.fd.write(_("D/L Time")+Spaces["D/L Time"]+
|
||||
_("%.3f seconds\n") % urldata.downloadtime)
|
||||
if urldata.checktime:
|
||||
self.fd.write("Check Time %.3f seconds\n" % urldata.checktime)
|
||||
self.fd.write(_("Check Time")+Spaces["Check Time"]+
|
||||
_("%.3f seconds\n") % urldata.checktime)
|
||||
if urldata.infoString:
|
||||
self.fd.write("Info "+StringUtil.indent(
|
||||
StringUtil.blocktext(urldata.infoString, 65), 11)+"\n")
|
||||
self.fd.write(_("Info")+Spaces["Info"]+
|
||||
StringUtil.indent(
|
||||
StringUtil.blocktext(urldata.infoString, 65),
|
||||
MaxIndent)+"\n")
|
||||
if urldata.warningString:
|
||||
self.warnings = self.warnings+1
|
||||
self.fd.write("Warning "+StringUtil.indent(
|
||||
StringUtil.blocktext(urldata.warningString, 65), 11)+"\n")
|
||||
self.fd.write(_("Warning")+Spaces["Warning"]+
|
||||
StringUtil.indent(
|
||||
StringUtil.blocktext(urldata.warningString, 65),
|
||||
MaxIndent)+"\n")
|
||||
|
||||
self.fd.write("Result ")
|
||||
self.fd.write(_("Result")+Spaces["Result"])
|
||||
if urldata.valid:
|
||||
self.fd.write(urldata.validString+"\n")
|
||||
else:
|
||||
|
|
@ -114,21 +127,21 @@ class StandardLogger:
|
|||
|
||||
|
||||
def endOfOutput(self):
|
||||
self.fd.write("\nThats it. ")
|
||||
self.fd.write(_("\nThats it. "))
|
||||
|
||||
if self.warnings==1:
|
||||
self.fd.write("1 warning, ")
|
||||
self.fd.write(_("1 warning, "))
|
||||
else:
|
||||
self.fd.write(str(self.warnings)+" warnings, ")
|
||||
self.fd.write(str(self.warnings)+_(" warnings, "))
|
||||
if self.errors==1:
|
||||
self.fd.write("1 error")
|
||||
self.fd.write(_("1 error"))
|
||||
else:
|
||||
self.fd.write(str(self.errors)+" errors")
|
||||
self.fd.write(" found.\n")
|
||||
self.fd.write(str(self.errors)+_(" errors"))
|
||||
self.fd.write(_(" found.\n"))
|
||||
self.stoptime = time.time()
|
||||
self.fd.write("Stopped checking at "+_strtime(self.stoptime)+
|
||||
(" (%.3f seconds)" % (self.stoptime - self.starttime))+
|
||||
"\n")
|
||||
self.fd.write(_("Stopped checking at ")+_strtime(self.stoptime)+
|
||||
(_(" (%.3f seconds)") %
|
||||
(self.stoptime - self.starttime))+"\n")
|
||||
self.fd.flush()
|
||||
self.fd = None
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,15 @@ This is the only entry point into the linkcheck module and is used
|
|||
of course by the linkchecker script.
|
||||
"""
|
||||
|
||||
# i18n suppport
|
||||
try:
|
||||
import fintl
|
||||
gettext = fintl.gettext
|
||||
fintl.bindtextdomain('linkcheck')
|
||||
fintl.textdomain('linkcheck')
|
||||
except ImportError:
|
||||
def gettext(msg):
|
||||
return msg
|
||||
import Config,UrlData,OutputReader,sys,lc_cgi
|
||||
|
||||
def checkUrls(config = Config.Configuration()):
|
||||
|
|
@ -24,5 +33,5 @@ def checkUrls(config = Config.Configuration()):
|
|||
except KeyboardInterrupt:
|
||||
config.finish()
|
||||
config.log_endOfOutput()
|
||||
sys.exit(1) # this is not good(tm)
|
||||
sys.exit(1) # XXX this is not good(tm)
|
||||
config.log_endOfOutput()
|
||||
|
|
|
|||
19
linkcheck/messages.po
Normal file
19
linkcheck/messages.po
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# German .po file for my LinkChecker.
|
||||
# Copyright (C) YEAR Free Software Foundation, Inc.
|
||||
# Bastian Kleineidam <calvin@users.sourceforge.net>, 2000.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: LinkChecker 1.2.3\n"
|
||||
"POT-Creation-Date: 2000-04-30 22:43+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Bastian Kleineidam <calvin@users.sourceforge.net>\n"
|
||||
"Language-Team: German <de@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=ISO-8859-1\n"
|
||||
"Content-Transfer-Encoding: 8-bit\n"
|
||||
|
||||
#: Logging.py:91
|
||||
msgid "Parent URL "
|
||||
msgstr "Vater URL "
|
||||
Loading…
Reference in a new issue