fe8eb2c01e
Now the headings in the ulf files for .desktop files are in the form [filename_Key] Gallery names are also adjusted to fit the new scheme, where there is no longer a need to pass a --key argument to desktop-translate.py Sync comments with .desktop files and the remaining .ulf and remove obsolete Mandriva Linux meta data while at it. Script to mass-replace relevant names in translations will be provided to infra. Change-Id: I87e8028aa5b66f5f5560efa62ddd9b1e5b61c49c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138455 Tested-by: Jenkins Reviewed-by: Sophie Gautier <sophi@libreoffice.org> Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice@googlemail.com>
172 lines
6.7 KiB
Python
172 lines
6.7 KiB
Python
#
|
|
# This file is part of the LibreOffice project.
|
|
#
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
#
|
|
# This file incorporates work covered by the following license notice:
|
|
#
|
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
# contributor license agreements. See the NOTICE file distributed
|
|
# with this work for additional information regarding copyright
|
|
# ownership. The ASF licenses this file to you under the Apache
|
|
# License, Version 2.0 (the "License"); you may not use this file
|
|
# except in compliance with the License. You may obtain a copy of
|
|
# the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
#
|
|
|
|
"""Translates multiple .desktop files at once with strings from .ulf
|
|
files; if you add new translatable .ulf files please add them to
|
|
l10ntools/source/localize.cxx in case the module is not already listed."""
|
|
|
|
import os
|
|
import sys
|
|
import argparse
|
|
import io
|
|
|
|
|
|
def encode_desktop_string(s_value):
|
|
"""Function encoding strings to be used as values in .desktop files."""
|
|
# <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#
|
|
# value-types> says "The escape sequences \s, \n, \t, \r, and \\ are supported for values of
|
|
# type string and localestring, meaning ASCII space, newline, tab, carriage return, and
|
|
# backslash, respectively." <https://specifications.freedesktop.org/desktop-entry-spec/
|
|
# desktop-entry-spec-1.1.html#basic-format> says "A file is interpreted as a series of lines
|
|
# that are separated by linefeed characters", so it is apparently necessary to escape at least
|
|
# linefeed and backslash characters. It is unclear why that spec talks about "linefeed" in
|
|
# one place and about "newline" ("\n") and "carriage return" ("\r") in another, and how they are
|
|
# supposed to relate, so just escape any U+000A LINE FEED as "\n" and any U+000D CARRIAGE RETURN
|
|
# as "\r"; it is unclear exactly which occurrences of U+0020 SPACE and U+0009 CHARACTER
|
|
# TABULATION would need to be escaped, so they are mostly left unescaped, for readability:
|
|
s_value = s_value.replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r")
|
|
if s_value.startswith(" "):
|
|
# <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#
|
|
# entries> says "Space before and after the equals sign should be ignored", so escape a
|
|
# leading U+0020 SPACE as "\s" (while it is not clear whether "space" there means just
|
|
# U+0020 SPACE or any kind of white space, in which case at least a leading U+0009 CHARACTER
|
|
# TABULATION should similarly be escaped as "\t"; also, it is unclear whether such
|
|
# characters should also be escaped at the end):
|
|
s_value = "\\s" + s_value[1:]
|
|
return s_value
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("-p", dest="productname", default="LibreOffice")
|
|
parser.add_argument("-d", dest="workdir", default=".")
|
|
parser.add_argument("--prefix", dest="prefix", default="")
|
|
parser.add_argument("--ext", dest="ext")
|
|
parser.add_argument("--template-dir", dest="template_dir", default=None)
|
|
parser.add_argument("ifile")
|
|
|
|
o = parser.parse_args()
|
|
|
|
if o.template_dir is None:
|
|
template_dir = f"{o.workdir}/{o.prefix}"
|
|
else:
|
|
template_dir = o.template_dir
|
|
|
|
templates = {}
|
|
|
|
# open input file
|
|
source = io.open(o.ifile, encoding="utf-8")
|
|
|
|
template = None
|
|
|
|
# read ulf file
|
|
for line in source:
|
|
if line.strip() == "":
|
|
continue
|
|
# the headings in the ulf files for .desktop files are in the form [filename_Key]
|
|
if line[0] == "[":
|
|
heading = line.split("]", 1)[0][1:]
|
|
template = heading.split("_", 1)[0]
|
|
key = heading.split("_", 1)[1]
|
|
entry = {}
|
|
# For every section in the specified ulf file there should exist
|
|
# a template file in $workdir ..
|
|
entry["outfile"] = f"{template_dir}{template}.{o.ext}"
|
|
entry["translations"] = {}
|
|
entry["key"] = key
|
|
templates[heading] = entry
|
|
else:
|
|
# split locale = "value" into 2 strings
|
|
if " = " not in line:
|
|
continue
|
|
locale, value = line.split(" = ")
|
|
|
|
if locale != line:
|
|
# replace en-US with en
|
|
locale = locale.replace("en-US", "en")
|
|
|
|
# use just anything inside the ""
|
|
assert value[0] == '"'
|
|
# Some entries span multiple lines.
|
|
# An entry will always end on a double quote.
|
|
while not value.endswith('"\n'):
|
|
value += source.readline()
|
|
value = value[1:-2]
|
|
|
|
# replace resource placeholder
|
|
value = value.replace("%PRODUCTNAME", o.productname)
|
|
|
|
locale = locale.replace("-", "_")
|
|
|
|
templates[heading]["translations"][locale] = value
|
|
|
|
source.close()
|
|
|
|
processed = 0
|
|
# process templates
|
|
for template, entries in templates.items():
|
|
outfilename = entries["outfile"]
|
|
|
|
# open the template file - ignore sections for which no
|
|
# templates exist
|
|
try:
|
|
template_file = io.open(outfilename, encoding="utf-8")
|
|
except OSError:
|
|
# string files processed one by one
|
|
if o.ext == "str":
|
|
continue
|
|
sys.exit(
|
|
f"Warning: No template found for item '{template}' : '{outfilename}'\n"
|
|
)
|
|
processed += 1
|
|
|
|
# open output file
|
|
tmpfilename = f"{outfilename}.tmp"
|
|
outfile = io.open(tmpfilename, "w", encoding="utf-8")
|
|
|
|
# emit the template to the output file
|
|
for line in template_file:
|
|
keyline = line
|
|
if keyline.startswith(entries["key"]):
|
|
# hack for Unity section
|
|
if entries["key"] == "UnityQuickList":
|
|
OUTKEY = "Name"
|
|
else:
|
|
OUTKEY = entries["key"]
|
|
keyline = OUTKEY + keyline[len(entries["key"]) :]
|
|
outfile.write(keyline)
|
|
if entries["key"] in line:
|
|
translations = entries["translations"]
|
|
for locale in sorted(translations.keys()):
|
|
value = translations.get(locale, None)
|
|
if value:
|
|
if o.ext in ("desktop", "str"):
|
|
if o.ext == "desktop":
|
|
value = encode_desktop_string(value)
|
|
outfile.write(f"{OUTKEY}[{locale}]={value}\n")
|
|
else:
|
|
outfile.write(f"\t[{locale}]{OUTKEY}={value}\n")
|
|
|
|
template_file.close()
|
|
|
|
outfile.close()
|
|
if os.path.exists(outfilename):
|
|
os.unlink(outfilename)
|
|
os.rename(tmpfilename, outfilename)
|
|
|
|
if o.ext == "str" and processed == 0:
|
|
sys.exit("Warning: No matching templates processed")
|