forked from openlp/openlp
Reworked the translation script.
Renamed the translation files to just their language codes for easier integration into translation tools.
This commit is contained in:
parent
40efcbfb8e
commit
d4ce60534a
@ -2993,7 +2993,7 @@ The content encoding is not UTF-8.</translation>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="openlp/plugins/presentations/lib/mediaitem.py" line="62"/>
|
<location filename="openlp/plugins/presentations/lib/mediaitem.py" line="62"/>
|
||||||
<source>Presentation</source>
|
<source>Presentation</source>
|
||||||
<translation type="unfinished">Presentation</translation>
|
<translation>Presentation</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="openlp/plugins/presentations/lib/mediaitem.py" line="78"/>
|
<location filename="openlp/plugins/presentations/lib/mediaitem.py" line="78"/>
|
@ -24,13 +24,31 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Short description
|
|
||||||
# Steps for creating languages:
|
|
||||||
# 1. make sure that the openlp_en.ts file exist
|
|
||||||
# 2. go to scripts folder and start:
|
|
||||||
# python translation_utils.py -a
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
This script is used to maintain the translation files in OpenLP. It downloads
|
||||||
|
the latest translation files from the Pootle translation server, updates the
|
||||||
|
local translation files from both the source code and the files from Pootle,
|
||||||
|
and can also generate the compiled translation files.
|
||||||
|
|
||||||
|
Create New Language
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
To create a new language, simply run this script with the ``-a`` command line
|
||||||
|
option::
|
||||||
|
|
||||||
|
@:~$ ./translation_utils.py -a
|
||||||
|
|
||||||
|
Update Translation Files
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The best way to update the translations is to download the files from Pootle,
|
||||||
|
and then update the local files using both the downloaded files and the source.
|
||||||
|
This is done easily via the ``-d``, ``-p`` and ``-u`` options::
|
||||||
|
|
||||||
|
@:~$ ./translation_utils.py -dpu
|
||||||
|
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
import urllib
|
import urllib
|
||||||
import re
|
import re
|
||||||
@ -39,201 +57,277 @@ from optparse import OptionParser
|
|||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
from BeautifulSoup import BeautifulSoup
|
from BeautifulSoup import BeautifulSoup
|
||||||
|
|
||||||
class TranslationUtils(object):
|
SERVER_URL = u'http://pootle.projecthq.biz/export/openlp/'
|
||||||
|
IGNORED_PATHS = [u'scripts']
|
||||||
|
IGNORED_FILES = [u'setup.py']
|
||||||
|
|
||||||
|
verbose_mode = False
|
||||||
|
|
||||||
|
class Command(object):
|
||||||
|
"""
|
||||||
|
Provide an enumeration of commands.
|
||||||
|
"""
|
||||||
|
Download = 1
|
||||||
|
Create = 2
|
||||||
|
Prepare = 3
|
||||||
|
Update = 4
|
||||||
|
Generate = 5
|
||||||
|
|
||||||
|
class CommandStack(object):
|
||||||
|
"""
|
||||||
|
This class provides an iterable stack.
|
||||||
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.ignore_paths = [u'./scripts']
|
self.current_index = 0
|
||||||
self.ignore_files = [u'setup.py']
|
self.data = []
|
||||||
self.server_url = u'http://pootle.projecthq.biz/export/openlp/'
|
|
||||||
self.cmd_stack = []
|
|
||||||
self.stack_count = 0
|
|
||||||
self.verbose = False
|
|
||||||
|
|
||||||
|
|
||||||
def process_stack(self):
|
def __len__(self):
|
||||||
if len(self.cmd_stack) > 0:
|
return len(self.data)
|
||||||
if len(self.cmd_stack) == self.stack_count:
|
|
||||||
print u'Process %d commands' % self.stack_count
|
def __getitem__(self, index):
|
||||||
print u'%d. ' % (self.stack_count-len(self.cmd_stack)+1),
|
if self.data[index].get(u'arguments'):
|
||||||
command = self.cmd_stack.pop(0)
|
return self.data[index][u'command'], self.data[index][u'arguments']
|
||||||
if len(command) > 1:
|
|
||||||
command[0](command[1])
|
|
||||||
else:
|
|
||||||
command[0]()
|
|
||||||
else:
|
else:
|
||||||
print "Finished all commands"
|
return self.data[index][u'command']
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
if self.current_index == len(self.data):
|
||||||
|
raise StopIteration
|
||||||
|
else:
|
||||||
|
current_item = self.data[self.current_index][u'command']
|
||||||
|
self.current_index += 1
|
||||||
|
return current_item
|
||||||
|
|
||||||
|
def append(self, command, **kwargs):
|
||||||
|
data = {u'command': command}
|
||||||
|
if u'arguments' in kwargs:
|
||||||
|
data[u'arguments'] = kwargs[u'arguments']
|
||||||
|
self.data.append(data)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.current_index = 0
|
||||||
|
|
||||||
|
|
||||||
def downloadTranslations(self):
|
def print_verbose(text):
|
||||||
print 'Download Translation files from HQ-Server'
|
"""
|
||||||
page = urllib.urlopen(u'%s' % (self.server_url))
|
This method checks to see if we are in verbose mode, and if so prints
|
||||||
soup = BeautifulSoup(page)
|
``text`` out.
|
||||||
languages = soup.findAll(text=re.compile(".*\.ts"))
|
|
||||||
for language in languages:
|
|
||||||
filename = os.path.join(u'..', u'resources', u'i18n',
|
|
||||||
u'openlp_%s' % language)
|
|
||||||
self.printVerbose(u'Get Translation File: %s' % filename)
|
|
||||||
self.get_and_write_file(language, filename)
|
|
||||||
print u' done'
|
|
||||||
self.process_stack()
|
|
||||||
|
|
||||||
def get_and_write_file(self, language, filename):
|
``text``
|
||||||
page = urllib.urlopen(u'%s%s' % (self.server_url, language))
|
The text to print.
|
||||||
content = page.read().decode('utf8')
|
"""
|
||||||
page.close()
|
global verbose_mode
|
||||||
file = open(filename, u'w')
|
if verbose_mode:
|
||||||
file.write(content.encode('utf8'))
|
print u' %s' % text
|
||||||
file.close()
|
|
||||||
|
|
||||||
def creation(self, language):
|
|
||||||
print "Create new Translation File"
|
|
||||||
"""
|
|
||||||
Use this option to create a new translation file
|
|
||||||
this function:
|
|
||||||
* create the new *.ts file
|
|
||||||
"""
|
|
||||||
filename = os.path.join(u'..', u'resources', u'i18n',
|
|
||||||
u'openlp_%s.ts' % language)
|
|
||||||
self.get_and_write_file(u'en.ts', filename)
|
|
||||||
self.printVerbose("""
|
|
||||||
Please remind: For permanent providing this language:
|
|
||||||
this language name have to append to the global list
|
|
||||||
variable "translations" in this file
|
|
||||||
and this file have to be uploaded to the Pootle Server
|
|
||||||
Please contact the developers!
|
|
||||||
""")
|
|
||||||
print u' done'
|
|
||||||
self.process_stack()
|
|
||||||
|
|
||||||
|
|
||||||
def preparation(self):
|
|
||||||
print u'Generating the openlp.pro file'
|
|
||||||
stringlist = []
|
|
||||||
start_dir = os.path.join(u'..')
|
|
||||||
for root, dirs, files in os.walk(start_dir):
|
|
||||||
for file in files:
|
|
||||||
path = u'%s' % root
|
|
||||||
path = path.replace('\\','/')
|
|
||||||
path = path.replace('..','.')
|
|
||||||
|
|
||||||
if file.startswith(u'hook-') or file.startswith(u'test_'):
|
|
||||||
continue
|
|
||||||
|
|
||||||
cond = False
|
def run(command):
|
||||||
for search in self.ignore_paths:
|
"""
|
||||||
if path.startswith(search):
|
This method runs an external application.
|
||||||
cond = True
|
|
||||||
if cond:
|
``command``
|
||||||
continue
|
The command to run.
|
||||||
cond = False
|
"""
|
||||||
for search in self.ignore_files:
|
print_verbose(command)
|
||||||
if search == file:
|
process = QtCore.QProcess()
|
||||||
cond = True
|
process.start(command)
|
||||||
if cond:
|
while (process.waitForReadyRead()):
|
||||||
continue
|
print_verbose(u'ReadyRead: %s' % QtCore.QString(process.readAll()))
|
||||||
|
print_verbose(u'Error(s):\n%s' % process.readAllStandardError())
|
||||||
if file.endswith(u'.py'):
|
print_verbose(u'Output:\n%s' % process.readAllStandardOutput())
|
||||||
|
print u' Done.'
|
||||||
|
|
||||||
|
def download_file(source_filename, dest_filename):
|
||||||
|
"""
|
||||||
|
Download a file and save it to disk.
|
||||||
|
|
||||||
|
``source_filename``
|
||||||
|
The file to download.
|
||||||
|
|
||||||
|
``dest_filename``
|
||||||
|
The new local file name.
|
||||||
|
"""
|
||||||
|
print_verbose(u'Downloading from: %s' % (SERVER_URL + source_filename))
|
||||||
|
page = urllib.urlopen(SERVER_URL + source_filename)
|
||||||
|
content = page.read().decode('utf8')
|
||||||
|
page.close()
|
||||||
|
file = open(dest_filename, u'w')
|
||||||
|
file.write(content.encode('utf8'))
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
def download_translations():
|
||||||
|
"""
|
||||||
|
This method downloads the translation files from the Pootle server.
|
||||||
|
"""
|
||||||
|
print 'Download translation files from Pootle'
|
||||||
|
page = urllib.urlopen(SERVER_URL)
|
||||||
|
soup = BeautifulSoup(page)
|
||||||
|
languages = soup.findAll(text=re.compile(r'.*\.ts'))
|
||||||
|
for language in languages:
|
||||||
|
filename = os.path.join(os.path.abspath(u'..'), u'resources', u'i18n',
|
||||||
|
language)
|
||||||
|
print_verbose(u'Get Translation File: %s' % filename)
|
||||||
|
download_file(language, filename)
|
||||||
|
print u' Done.'
|
||||||
|
|
||||||
|
def prepare_project():
|
||||||
|
"""
|
||||||
|
This method creates the project file needed to update the translation files
|
||||||
|
and compile them into .qm files.
|
||||||
|
"""
|
||||||
|
print u'Generating the openlp.pro file'
|
||||||
|
lines = []
|
||||||
|
start_dir = os.path.abspath(u'..')
|
||||||
|
start_dir = start_dir + os.sep
|
||||||
|
print_verbose(u'Starting directory: %s' % start_dir)
|
||||||
|
for root, dirs, files in os.walk(start_dir):
|
||||||
|
for file in files:
|
||||||
|
path = root.replace(start_dir, u'').replace(u'\\', u'/') #.replace(u'..', u'.')
|
||||||
|
if file.startswith(u'hook-') or file.startswith(u'test_'):
|
||||||
|
continue
|
||||||
|
ignore = False
|
||||||
|
for ignored_path in IGNORED_PATHS:
|
||||||
|
if path.startswith(ignored_path):
|
||||||
|
ignore = True
|
||||||
|
break
|
||||||
|
if ignore:
|
||||||
|
continue
|
||||||
|
ignore = False
|
||||||
|
for ignored_file in IGNORED_FILES:
|
||||||
|
if file == ignored_file:
|
||||||
|
ignore = True
|
||||||
|
break
|
||||||
|
if ignore:
|
||||||
|
continue
|
||||||
|
if file.endswith(u'.py') or file.endswith(u'.pyw'):
|
||||||
|
if path:
|
||||||
line = u'%s/%s' % (path, file)
|
line = u'%s/%s' % (path, file)
|
||||||
self.printVerbose(u'Parsing "%s"' % line)
|
else:
|
||||||
stringlist.append(u'SOURCES += %s' % line)
|
line = file
|
||||||
elif file.endswith(u'.pyw'):
|
print_verbose(u'Parsing "%s"' % line)
|
||||||
line = u'%s/%s' % (path, file)
|
lines.append(u'SOURCES += %s' % line)
|
||||||
self.printVerbose(u'Parsing "%s"' % line)
|
elif file.endswith(u'.ts'):
|
||||||
stringlist.append(u'SOURCES += %s' % line)
|
line = u'%s/%s' % (path, file)
|
||||||
elif file.endswith(u'.ts'):
|
print_verbose(u'Parsing "%s"' % line)
|
||||||
line = u'%s/%s' % (path, file)
|
lines.append(u'TRANSLATIONS += %s' % line)
|
||||||
self.printVerbose(u'Parsing "%s"' % line)
|
lines.sort()
|
||||||
stringlist.append(u'TRANSLATIONS += %s' % line)
|
file = open(os.path.join(start_dir, u'openlp.pro'), u'w')
|
||||||
|
file.write(u'\n'.join(lines).encode('utf8'))
|
||||||
stringlist.sort()
|
file.close()
|
||||||
self.write_file(os.path.join(start_dir, u'openlp.pro'), stringlist)
|
print u' Done.'
|
||||||
print u' done'
|
|
||||||
self.process_stack()
|
|
||||||
|
|
||||||
def update(self):
|
def update_translations():
|
||||||
print u'Update the translation files'
|
print u'Update the translation files'
|
||||||
cmd = u'pylupdate4 -verbose -noobsolete ../openlp.pro'
|
if not os.path.exists(os.path.join(os.path.abspath(u'..'), u'openlp.pro')):
|
||||||
self.start_cmd(cmd)
|
print u'You have no generated a project file yet, please run this ' + \
|
||||||
|
u'script with the -p option.'
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
os.chdir(os.path.abspath(u'..'))
|
||||||
|
run(u'pylupdate4 -verbose -noobsolete openlp.pro')
|
||||||
|
|
||||||
def generate(self):
|
def generate_binaries():
|
||||||
print u'Generate the related *.qm files'
|
print u'Generate the related *.qm files'
|
||||||
cmd = u'lrelease ../openlp.pro'
|
if not os.path.exists(os.path.join(os.path.abspath(u'..'), u'openlp.pro')):
|
||||||
self.start_cmd(cmd)
|
print u'You have no generated a project file yet, please run this ' + \
|
||||||
|
u'script with the -p option. It is also recommended that you ' + \
|
||||||
def write_file(self, filename, stringlist):
|
u'this script with the -u option to update the translation ' + \
|
||||||
content = u''
|
u'files as well.'
|
||||||
for line in stringlist:
|
return
|
||||||
content = u'%s%s\n' % (content, line)
|
else:
|
||||||
file = open(filename, u'w')
|
os.chdir(os.path.abspath(u'..'))
|
||||||
file.write(content.encode('utf8'))
|
run(u'lrelease openlp.pro')
|
||||||
file.close()
|
|
||||||
|
|
||||||
def printVerbose(self, data):
|
def create_translation(language):
|
||||||
if self.verbose:
|
"""
|
||||||
print u' %s' % data
|
This method creates a new translation file.
|
||||||
|
|
||||||
def start_cmd(self, command):
|
``language``
|
||||||
self.printVerbose(command)
|
The language file to create.
|
||||||
self.process = QtCore.QProcess()
|
"""
|
||||||
self.process.start(command)
|
print "Create new Translation File"
|
||||||
while (self.process.waitForReadyRead()):
|
filename = os.path.join(os.path.abspath(u'..'), u'resources', u'i18n', language)
|
||||||
self.printVerbose(u'ReadyRead: %s' % QtCore.QString(self.process.readAll()))
|
download_file(u'en.ts', filename)
|
||||||
self.printVerbose(self.process.readAllStandardError())
|
print u'\n** Please Note **\n'
|
||||||
self.printVerbose(self.process.readAllStandardOutput())
|
print u'In order to get this file into OpenLP and onto the Pootle ' + \
|
||||||
print u' done'
|
u'translation server you will need to subscribe to the OpenLP' + \
|
||||||
self.process_stack()
|
u'Translators mailing list, and request that your language file ' + \
|
||||||
|
u'be added to the project.\n'
|
||||||
|
print u' Done'
|
||||||
|
|
||||||
|
def process_stack(command_stack):
|
||||||
|
"""
|
||||||
|
This method looks at the commands in the command stack, and processes them
|
||||||
|
in the order they are in the stack.
|
||||||
|
|
||||||
|
``command_stack``
|
||||||
|
The command stack to process.
|
||||||
|
"""
|
||||||
|
if command_stack:
|
||||||
|
print u'Processing %d commands...' % len(command_stack)
|
||||||
|
for command in command_stack:
|
||||||
|
print u'%d.' % (command_stack.current_index),
|
||||||
|
if command == Command.Download:
|
||||||
|
download_translations()
|
||||||
|
elif command == Command.Prepare:
|
||||||
|
prepare_project()
|
||||||
|
elif command == Command.Update:
|
||||||
|
update_translations()
|
||||||
|
elif command == Command.Generate:
|
||||||
|
generate_binaries()
|
||||||
|
elif command == Command.Create:
|
||||||
|
command, arguments = command_stack[command_stack.current_index]
|
||||||
|
create_translation(*arguments)
|
||||||
|
print u'Finished processing commands.'
|
||||||
|
else:
|
||||||
|
print u'No commands to process.'
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# start Main Class
|
global verbose_mode
|
||||||
Util = TranslationUtils()
|
|
||||||
|
|
||||||
# Set up command line options.
|
# Set up command line options.
|
||||||
usage = u'''
|
usage = u'%prog [options]\nOptions are parsed in the order they are ' + \
|
||||||
This script handle the translation files for OpenLP.
|
u'listed below. If no options are given, "-dpug" will be used.\n\n' + \
|
||||||
Usage: %prog [options]
|
u'This script is used to manage OpenLP\'s translation files.'
|
||||||
If no option will be used, options "-d -p -u -g" will be set automatically
|
|
||||||
'''
|
|
||||||
parser = OptionParser(usage=usage)
|
parser = OptionParser(usage=usage)
|
||||||
parser.add_option('-d', '--download-ts', action='store_true',
|
parser.add_option('-d', '--download-ts', dest='download',
|
||||||
dest='download', help='Load languages from Pootle Server')
|
action='store_true', help='download language files from Pootle')
|
||||||
parser.add_option('-c', '--create', metavar='lang',
|
parser.add_option('-c', '--create', dest=u'create', metavar='LANG',
|
||||||
help='creation of new translation file, Parameter: language (e.g. "en_GB"')
|
help='create a new translation file for language LANG, e.g. "en_GB"')
|
||||||
parser.add_option('-p', '--prepare', action='store_true', dest='prepare',
|
parser.add_option('-p', '--prepare', dest='prepare', action='store_true',
|
||||||
help='preparation (generate pro file)')
|
help='generate a project file, used to update the translations')
|
||||||
parser.add_option('-u', '--update', action='store_true', dest='update',
|
parser.add_option('-u', '--update', action='store_true', dest='update',
|
||||||
help='update translation files')
|
help='update translation files (needs a project file)')
|
||||||
parser.add_option('-g', '--generate', action='store_true', dest='generate',
|
parser.add_option('-g', '--generate', dest='generate', action='store_true',
|
||||||
help='generate qm files')
|
help='compile .ts files into .qm files')
|
||||||
parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
|
parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
|
||||||
help='Give more informations while processing')
|
help='show extra information while processing translations')
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
# Create and populate the command stack
|
||||||
|
command_stack = CommandStack()
|
||||||
if options.download:
|
if options.download:
|
||||||
Util.cmd_stack.append([Util.downloadTranslations])
|
command_stack.append(Command.Download)
|
||||||
if options.create:
|
if options.create:
|
||||||
Util.cmd_stack.append([Util.creation, u'%s' % options.create])
|
command_stack.append(Command.Create, arguments=[options.create])
|
||||||
if options.prepare:
|
if options.prepare:
|
||||||
Util.cmd_stack.append([Util.preparation])
|
command_stack.append(Command.Prepare)
|
||||||
if options.update:
|
if options.update:
|
||||||
Util.cmd_stack.append([Util.update])
|
command_stack.append(Command.Update)
|
||||||
if options.generate:
|
if options.generate:
|
||||||
Util.cmd_stack.append([Util.generate])
|
command_stack.append(Command.Generate)
|
||||||
if options.verbose:
|
verbose_mode = options.verbose
|
||||||
Util.verbose = True
|
if not command_stack:
|
||||||
|
command_stack.append(Command.Download)
|
||||||
|
command_stack.append(Command.Prepare)
|
||||||
|
command_stack.append(Command.Update)
|
||||||
|
command_stack.append(Command.Generate)
|
||||||
|
# Process the commands
|
||||||
|
process_stack(command_stack)
|
||||||
|
|
||||||
if len(Util.cmd_stack) == 0:
|
|
||||||
Util.cmd_stack.append([Util.downloadTranslations])
|
|
||||||
Util.cmd_stack.append([Util.preparation])
|
|
||||||
Util.cmd_stack.append([Util.update])
|
|
||||||
Util.cmd_stack.append([Util.generate])
|
|
||||||
|
|
||||||
Util.stack_count = len(Util.cmd_stack)
|
|
||||||
Util.process_stack()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == u'__main__':
|
if __name__ == u'__main__':
|
||||||
if os.path.split(os.path.abspath(u'.'))[1] != u'scripts':
|
if os.path.split(os.path.abspath(u'.'))[1] != u'scripts':
|
||||||
print u'You need to run this script from the scripts directory.'
|
print u'You need to run this script from the scripts directory.'
|
||||||
else:
|
else:
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user