[3650] CalendarServer/trunk
Revision: 3650 http://trac.macosforge.org/projects/calendarserver/changeset/3650 Author: sagen@apple.com Date: 2009-02-09 08:57:03 -0800 (Mon, 09 Feb 2009) Log Message: ----------- At startup, scan for Apple .lproj translations and convert them to gnutext form Modified Paths: -------------- CalendarServer/trunk/calendarserver/tap/caldav.py CalendarServer/trunk/conf/caldavd-test.plist CalendarServer/trunk/twistedcaldav/config.py CalendarServer/trunk/twistedcaldav/localization.py CalendarServer/trunk/twistedcaldav/test/test_localization.py Added Paths: ----------- CalendarServer/trunk/locales/en_EN.ISO8859-1/ CalendarServer/trunk/locales/en_EN.ISO8859-1/LC_MESSAGES/ Removed Paths: ------------- CalendarServer/trunk/locales/en/ CalendarServer/trunk/locales/en_EN.ISO8859-1/LC_MESSAGES/ Modified: CalendarServer/trunk/calendarserver/tap/caldav.py =================================================================== --- CalendarServer/trunk/calendarserver/tap/caldav.py 2009-02-08 18:21:54 UTC (rev 3649) +++ CalendarServer/trunk/calendarserver/tap/caldav.py 2009-02-09 16:57:03 UTC (rev 3650) @@ -76,6 +76,7 @@ from twistedcaldav import memcachepool from twistedcaldav.notify import installNotificationClient from twistedcaldav.util import getNCPU +from twistedcaldav.localization import processLocalizationFiles try: from twistedcaldav.authkerb import NegotiateCredentialFactory @@ -717,6 +718,9 @@ def makeService_Combined(self, options): s = MultiService() + # Process localization string files + processLocalizationFiles(config.Localization) + # The logger service must come before the monitor service, otherwise # we won't know which logging port to pass to the slaves' command lines Modified: CalendarServer/trunk/conf/caldavd-test.plist =================================================================== --- CalendarServer/trunk/conf/caldavd-test.plist 2009-02-08 18:21:54 UTC (rev 3649) +++ CalendarServer/trunk/conf/caldavd-test.plist 2009-02-09 16:57:03 UTC (rev 3650) @@ -670,7 +670,7 @@ <key>LocalesDirectory</key> <string>locales</string> <key>Language</key> - <string>en</string> + <string>English</string> </dict> </dict> Modified: CalendarServer/trunk/twistedcaldav/config.py =================================================================== --- CalendarServer/trunk/twistedcaldav/config.py 2009-02-08 18:21:54 UTC (rev 3649) +++ CalendarServer/trunk/twistedcaldav/config.py 2009-02-09 16:57:03 UTC (rev 3650) @@ -344,8 +344,9 @@ # Localization # "Localization" : { - "LocalesDirectory" : "/usr/share/caldavd/locales", - "Language" : "en", + "TranslationsDirectory" : "/usr/share/caldavd/share/translations", + "LocalesDirectory" : "/usr/share/caldavd/share/locales", + "Language" : "English", }, Modified: CalendarServer/trunk/twistedcaldav/localization.py =================================================================== --- CalendarServer/trunk/twistedcaldav/localization.py 2009-02-08 18:21:54 UTC (rev 3649) +++ CalendarServer/trunk/twistedcaldav/localization.py 2009-02-09 16:57:03 UTC (rev 3650) @@ -1,5 +1,5 @@ ## -# Copyright (c) 2005-2008 Apple Inc. All rights reserved. +# Copyright (c) 2005-2009 Apple Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,6 +14,19 @@ # limitations under the License. ## +from __future__ import with_statement +import gettext +import inspect +import datetime +import os +import struct +import array +from locale import normalize +from twistedcaldav.config import config +from twistedcaldav.log import Logger + +log = Logger() + """ Localization module @@ -85,12 +98,6 @@ """ -import gettext -import inspect -import datetime -from twistedcaldav.config import config - - class translationTo(object): translations = {} @@ -333,3 +340,159 @@ _("NOV"), _("DEC"), ] + + + +## +# String file conversion routines +## + +def processLocalizationFiles(settings): + + lprojRoot = settings.TranslationsDirectory + gnuRoot = settings.LocalesDirectory + + # Do we have an Apple translations directory? + if lprojRoot and gnuRoot and os.path.exists(lprojRoot): + + log.info("Looking for Apple .lproj directories in %s" % (lprojRoot,)) + + # Make sure the gnutext translations directory exists + if not os.path.exists(gnuRoot): + os.mkdir(gnuRoot) + + # Scan for Apple translations (directories ending in .lproj) + for item in os.listdir(lprojRoot): + if item.endswith(".lproj"): + stringsFile = os.path.join(lprojRoot, item, + 'calendarserver.strings') + localeName = normalize(item[:-6]) + moFile = os.path.join(gnuRoot, localeName, 'LC_MESSAGES', + 'calendarserver.mo') + if os.path.exists(stringsFile): + if (not os.path.exists(moFile) or + os.stat(stringsFile).st_mtime > + os.stat(moFile).st_mtime): + log.info("Converting %s to %s" % (stringsFile, moFile)) + try: + convertStringsFile(stringsFile, moFile) + except Exception, e: + log.error("Failed to convert %s to %s: %s" % + (stringsFile, moFile, e)) + else: + log.info("%s is up to date" % (moFile,)) + +class ParseError(Exception): + pass + +def parseString(text, index=0): + + value = "" + + while index < len(text): + ch = text[index] + + if ch == '"': + if text[index-1] != "\\": + # At unescaped quote + if value: + # ...marking end of string; return it + return (value, index+1) + else: + # ...marking beginning of string; skip it + index += 1 + continue + + value += text[index] + index += 1 + + # no closing quote " + raise ParseError("No closing quote") + +def parseLine(line): + + key, index = parseString(line) + remaining = line[index:].strip() + if remaining[0] != "=": + raise ParseError("Expected equals sign") + remaining = remaining[1:].strip() + value, index = parseString(remaining) + return (key, value) + + +def convertStringsFile(src, dest): + strings = { } + + dir = os.path.dirname(dest) + + if not os.path.exists(dir): + try: + os.makedirs(dir) + except OSError: + # can't create directory to hold .po file + return + + with open(src) as input: + lines = input.readlines() + + for num, line in enumerate(lines): + line = line.strip() + if not line.startswith('"'): + continue + + try: + key, value = parseLine(line) + except ParseError, err: + log.error("Error on line %d of %s: %s" % (num+1, src, str(err))) + raise + + strings[key] = value + + # The format of GNUtext MO files is described here: + # http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html + + originals = strings.keys() + originals.sort() + + descriptors = [] + keys = '' + values = '' + + for original in originals: + translation = strings[original] + + descriptors.append((len(keys), len(original), len(values), + len(translation))) + keys += original + '\0' # <NUL> terminated + values += translation + '\0' + + # The header is 28 bytes, each descriptor is 8 bytes, with two descriptors + # per string (one pointing at original, one pointing at translation) + keysOffset = 28 + len(originals) * 2 * 8 + valuesOffset = keysOffset + len(keys) + + keyDescriptors = [] + valueDescriptors = [] + for origOffset, origLen, transOffset, transLen in descriptors: + keyDescriptors.append(origLen) + keyDescriptors.append(keysOffset + origOffset) + valueDescriptors.append(transLen) + valueDescriptors.append(valuesOffset + transOffset) + + result = struct.pack( + "Iiiiiii", + 0x950412DEL, # magic number + 0, # file format revision + len(originals), # number of strings + 28, # offset of table with original strings + 28+len(originals)*8, # offset of table with translation strings + 0, # size of hashing table + 0 # offset of hashing table + ) + result += array.array("i", keyDescriptors).tostring() + result += array.array("i", valueDescriptors).tostring() + result += keys + result += values + + with open(dest, "wb") as outFile: + outFile.write(result) Modified: CalendarServer/trunk/twistedcaldav/test/test_localization.py =================================================================== --- CalendarServer/trunk/twistedcaldav/test/test_localization.py 2009-02-08 18:21:54 UTC (rev 3649) +++ CalendarServer/trunk/twistedcaldav/test/test_localization.py 2009-02-09 16:57:03 UTC (rev 3650) @@ -62,7 +62,7 @@ def test_TimeFormattingAMPM(self): - with translationTo('en', localeDir=localeDir) as t: + with translationTo('English', localeDir=localeDir) as t: self.assertEquals(t.dtTime(time(0,0)), "12:00 AM") self.assertEquals(t.dtTime(time(12,0)), "12:00 PM") @@ -82,7 +82,7 @@ def test_CalendarFormatting(self): - with translationTo('en', localeDir=localeDir) as t: + with translationTo('English', localeDir=localeDir) as t: comp = data[0][1] self.assertEquals(t.date(comp), "Saturday, October 25, 2008")
participants (1)
-
source_changes@macosforge.org