Skip to content

Commit 0781719

Browse files
committed
Switch to generic .po[t] handling
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
1 parent 374532a commit 0781719

2 files changed

Lines changed: 92 additions & 174 deletions

File tree

mmdzanata/__init__.py

Lines changed: 24 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -196,34 +196,20 @@ def get_module_catalog_from_tags(session, tags, debug=False):
196196
return catalog
197197

198198

199-
def get_translated_locales(zanata_rest_url, zanata_project,
200-
zanata_project_version,
201-
debug=False):
202-
# Get the statistics on the translation project for this version
203-
stats_url = zanata_rest_url + "/stats/proj/%s/iter/%s" % (
204-
zanata_project, zanata_project_version)
205-
206-
r = requests.get(stats_url, headers={"Accept": "application/json"})
207-
if r.status_code == 404:
208-
print("Project '%s:%s' does not exist." % (
209-
zanata_project, zanata_project_version),
210-
file=sys.stderr)
211-
raise NonexistentProjectError(zanata_project, zanata_project_version)
212-
elif r.status_code != 200:
213-
raise UnexpectedHTTPResponse(r.status_code, r.content)
214-
215-
# We will pull down information for any locale that is at least partially
216-
# translated
217-
translated_locales = [t["locale"]
218-
for t in r.json()['stats']
219-
if t["translated"] > 0]
199+
def split_location(location):
200+
location_data = location.split(';')
201+
if len(location_data) < 3 or len(location_data) > 5:
202+
print("Invalid location clue in translation data: %s" % (
203+
location), file=sys.stderr)
220204

221-
if debug:
222-
print("Available locales: ")
223-
for locale in translated_locales:
224-
print("* %s" % locale)
205+
module_name = location_data[0]
206+
module_stream = location_data[1]
207+
profile_name = None
208+
translation_type = location_data[2]
209+
if translation_type == 'profile':
210+
profile_name = location_data[3]
225211

226-
return translated_locales
212+
return module_name, module_stream, profile_name, translation_type
227213

228214

229215
def get_modulemd_translations_from_catalog_dict(catalog_dict):
@@ -248,30 +234,25 @@ def get_modulemd_translations_from_catalog_dict(catalog_dict):
248234
continue
249235

250236
for location, _ in msg.locations:
251-
split_location = location.split(';')
252-
if len(split_location) < 3 or len(split_location) > 5:
253-
print("Invalid location clue in translation data: %s" % (
254-
location), file=sys.stderr)
255-
256-
module_name = split_location[0]
257-
module_stream = split_location[1]
237+
(module_name, module_stream, profile_name, translation_type)\
238+
= split_location(location)
258239

259240
try:
260241
entry = entries[(module_name, module_stream, locale)]
261242
except KeyError:
262243
entry = Modulemd.TranslationEntry.new(locale)
263244

264245
# Summary Translation
265-
if split_location[2] == "summary":
246+
if translation_type == "summary":
266247
entry.set_summary(msg.string)
267248

268249
# Description Translation
269-
elif split_location[2] == "description":
250+
elif translation_type == "description":
270251
entry.set_description(msg.string)
271252

272253
# Translation of profile descriptions
273-
elif split_location[2] == "profile":
274-
entry.set_profile_description(split_location[3],
254+
elif translation_type == "profile":
255+
entry.set_profile_description(profile_name,
275256
msg.string)
276257

277258
entries[(module_name, module_stream, locale)] = entry
@@ -300,38 +281,17 @@ def get_modulemd_translations_from_catalog_dict(catalog_dict):
300281
return mmd_translations.values()
301282

302283

303-
def get_modulemd_translations(zanata_rest_url, zanata_project,
304-
os_branch, zanata_translation_file,
284+
def get_modulemd_translations(translation_files,
305285
debug=False):
306-
translated_locales = get_translated_locales(zanata_rest_url,
307-
zanata_project,
308-
os_branch,
309-
debug)
310286

311287
catalogs = dict()
312-
for loc in translated_locales:
313-
# Get the translation data for this locale
314-
pofile_url = zanata_rest_url + \
315-
"/file/translation/%s/%s/%s/po?docId=%s" % (
316-
zanata_project, os_branch, loc,
317-
zanata_translation_file)
318-
r = requests.get(pofile_url,
319-
headers={"Accept": "application/octet-stream"})
320-
if r.status_code != 200:
321-
print("Could not retrieve translations for %s" % loc,
322-
file=sys.stderr)
323-
continue
324-
325-
if debug:
326-
print("PO content for locale '%s'" % loc)
327-
print(r.text)
328-
329-
# Read the po file into a catalog, indexed by the locale
330-
catalogs[loc] = pofile.read_po(
331-
BytesIO(r.content),
332-
domain=zanata_translation_file)
288+
for f in translation_files:
289+
with open(f, 'r') as infile:
290+
catalog = pofile.read_po(infile)
291+
catalogs[catalog.locale_identifier] = catalog
333292

334293
translations = get_modulemd_translations_from_catalog_dict(catalogs)
294+
335295
if debug:
336296
for translation in translations:
337297
print(translation.dumps())

mmdzanata/cli.py

Lines changed: 68 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@
1616
import click
1717
import gi
1818
import koji
19-
import mmdzanata
20-
import mmdzanata.fedora
2119
import os
20+
import os.path
2221
import subprocess
2322
import sys
2423
import shutil
@@ -29,6 +28,9 @@
2928
gi.require_version('Modulemd', '1.0')
3029
from gi.repository import Modulemd
3130

31+
from mmdzanata import get_module_catalog_from_tags, get_modulemd_translations
32+
from mmdzanata.fedora import get_fedora_rawhide_version, \
33+
get_tags_for_fedora_branch, KOJI_URL
3234

3335
##############################################################################
3436
# Common options for all commands #
@@ -38,36 +40,15 @@
3840
@click.group()
3941
@click.option('--debug/--no-debug', default=False)
4042
@click.option('-k', '--koji-url',
41-
default=mmdzanata.fedora.KOJI_URL,
43+
default=KOJI_URL,
4244
type=str, help="The URL of the Koji build system.",
4345
show_default=True,
4446
metavar="<URL>")
4547
@click.option('-b', '--branch', default="rawhide", type=str,
4648
help="The distribution release",
4749
metavar="<branch_name>")
48-
@click.option('-z', '--zanata-url',
49-
default=mmdzanata.fedora.ZANATA_URL,
50-
type=str, help="The Zanata URL",
51-
show_default=True,
52-
metavar="<zanata_project>")
53-
@click.option('-p', '--zanata-project',
54-
default=mmdzanata.fedora.ZANATA_PROJECT,
55-
type=str, help="The Zanata project",
56-
show_default=True,
57-
metavar="<zanata_project>")
58-
@click.option('-f', '--zanata-translation-document',
59-
default=mmdzanata.fedora.ZANATA_DOCUMENT,
60-
help="The name of the translated file in Zanata.",
61-
show_default=True,
62-
metavar="<translation_document>")
63-
@click.option('-c', '--zanata-user-config',
64-
default=lambda: "%s/.config/zanata.ini" % (
65-
os.environ.get("HOME", '~')),
66-
help="Path to the Zanata User Config INI file",
67-
type=click.Path(exists=True))
6850
@click.pass_context
69-
def cli(ctx, debug, branch, koji_url, zanata_url, zanata_project,
70-
zanata_translation_document, zanata_user_config):
51+
def cli(ctx, debug, branch, koji_url):
7152
"""Tools for managing modularity translations."""
7253

7354
ctx.obj = dict()
@@ -78,13 +59,7 @@ def cli(ctx, debug, branch, koji_url, zanata_url, zanata_project,
7859
ctx.obj['branch'] = branch
7960

8061
if branch == "rawhide":
81-
ctx.obj['branch'] = mmdzanata.fedora.get_fedora_rawhide_version(
82-
ctx.obj['session'])
83-
84-
ctx.obj['zanata_url'] = zanata_url
85-
ctx.obj['zanata_project'] = zanata_project
86-
ctx.obj['zanata_translation_document'] = zanata_translation_document
87-
ctx.obj['zanata_user_config'] = zanata_user_config
62+
ctx.obj['branch'] = get_fedora_rawhide_version(ctx.obj['session'])
8863

8964
##############################################################################
9065
# Subcommands #
@@ -96,114 +71,97 @@ def cli(ctx, debug, branch, koji_url, zanata_url, zanata_project,
9671

9772

9873
@cli.command()
99-
@click.option('--upload/--no-upload', default=False,
100-
help='Whether to automatically push extracted strings to '
101-
'Zanata',
102-
show_default=True)
74+
@click.option('-p', '--pot-file',
75+
default='fedora-modularity-translations.pot',
76+
type=click.File(mode='wb', atomic=True, lazy=True),
77+
show_default=True,
78+
metavar="<PATH>",
79+
help="Path to the portable object template (POT) file to hold "
80+
"the translatable strings.")
10381
@click.pass_context
104-
def extract(ctx, upload):
82+
def extract(ctx, pot_file):
10583
"""
10684
Extract translatable strings from modules.
10785
10886
Extract translations from all modules included in a particular version of
10987
Fedora or EPEL.
11088
"""
11189

112-
catalog = mmdzanata.get_module_catalog_from_tags(
113-
ctx.parent.obj['session'], mmdzanata.fedora.get_tags_for_fedora_branch(
90+
catalog = get_module_catalog_from_tags(
91+
ctx.parent.obj['session'], get_tags_for_fedora_branch(
11492
ctx.parent.obj['branch']),
11593
debug=ctx.parent.obj['debug'])
11694

117-
# Create a temporary directory to hold data while we generate it
118-
tdir = tempfile.mkdtemp()
119-
120-
po_basename = "%s.pot" % ctx.parent.obj['zanata_translation_document']
121-
potfile = "%s/%s" % (tdir, po_basename)
122-
123-
with open(potfile, mode="wb") as f:
124-
pofile.write_po(f, catalog, sort_by_file=True)
125-
126-
# Optionally upload the extracted strings directly to Zanata
127-
if upload:
128-
# Use the zanata-cli to upload the pot file
129-
# It would be better to use the REST API directly here, but the XML
130-
# payload format is not documented.
131-
132-
# First ensure that the requested branch exists in Zanata
133-
zanata_args = [
134-
'/usr/bin/zanata-cli', '-B', '-e', 'put-version',
135-
'--url', ctx.parent.obj['zanata_url'],
136-
'--version-project', ctx.parent.obj['zanata_project'],
137-
'--version-slug', ctx.parent.obj['branch'],
138-
'--user-config', ctx.parent.obj['zanata_user_config']
139-
]
140-
result = subprocess.run(zanata_args, capture_output=True)
141-
if result.returncode or ctx.parent.obj['debug']:
142-
print(result.stderr.decode('utf-8'))
143-
print(result.stdout.decode('utf-8'))
144-
if result.returncode:
145-
sys.exit(1)
146-
147-
# Update the translatable strings for this branch
148-
zanata_args = [
149-
'/usr/bin/zanata-cli', '-B', '-e', 'push',
150-
'--url', ctx.parent.obj['zanata_url'],
151-
'--project', ctx.parent.obj['zanata_project'],
152-
'--project-type', 'gettext',
153-
'--project-version', ctx.parent.obj['branch'],
154-
'--src-dir', tdir,
155-
'--user-config', ctx.parent.obj['zanata_user_config']
156-
]
157-
result = subprocess.run(zanata_args, capture_output=True)
158-
if result.returncode or ctx.parent.obj['debug']:
159-
print(result.stderr.decode('utf-8'))
160-
print(result.stdout.decode('utf-8'))
161-
if result.returncode:
162-
sys.exit(2)
163-
164-
print("Uploaded translatable strings for %s to Zanata" % (
165-
ctx.parent.obj['branch']))
166-
167-
else:
168-
# Move the temporary path to the current directory
169-
shutil.move(potfile, po_basename)
170-
print("Wrote extracted strings for %s to %s" % (ctx.obj['branch'],
171-
po_basename))
172-
# Clean up the temporary directory
173-
shutil.rmtree(tdir)
95+
pofile.write_po(pot_file, catalog, sort_by_file=True)
96+
97+
print("Wrote extracted strings for %s to %s" % (ctx.obj['branch'],
98+
pot_file.name))
17499

175100

176101
##############################################################################
177102
# `mmdzanata generate_metadata` #
178103
##############################################################################
179104

180105
@cli.command()
106+
@click.option('-d', '--pofile-dir',
107+
default='.',
108+
help="Path to a directory containing portable object (.po) "
109+
"translation files",
110+
type=click.Path(exists=True, dir_okay=True, resolve_path=True,
111+
readable=True))
112+
@click.option('-y', '--yaml-file',
113+
default='fedora-modularity-translations.yaml',
114+
type=click.File(mode='wb', atomic=True, lazy=True),
115+
show_default=True,
116+
metavar="<PATH>",
117+
help="Path to the YAML file to hold the translated strings in "
118+
"modulemd-translations format.")
181119
@click.pass_context
182-
def generate_metadata(ctx):
120+
def generate_metadata(ctx, pofile_dir, yaml_file):
183121
"""
184122
Generate modulemd-translations YAML.
185123
186124
:return: 0 on successful creation of modulemd-translation,
187125
nonzero on failure.
188126
"""
189127

190-
zanata_rest_url = "%s/rest" % ctx.parent.obj['zanata_url']
128+
# Process all .po files in the provided directory
129+
translation_files = [f for f in os.listdir(pofile_dir) if
130+
os.path.isfile((os.path.join(pofile_dir, f))) and
131+
f.endswith(".po")]
132+
translations = get_modulemd_translations(translation_files,
133+
debug=ctx.parent.obj['debug'])
134+
135+
yaml_file.write(Modulemd.dumps(sorted(translations)).encode('utf-8'))
136+
137+
print("Wrote modulemd-translations YAML to %s" % yaml_file.name)
138+
139+
140+
@cli.command()
141+
142+
@click.pass_context
143+
def experiment(ctx, pofile_dir):
144+
"""
145+
Experiment with Babel
146+
"""
191147

192-
translations = mmdzanata.get_modulemd_translations(
193-
zanata_rest_url,
194-
ctx.parent.obj['zanata_project'],
195-
ctx.parent.obj['branch'],
196-
ctx.parent.obj['zanata_translation_document'],
197-
ctx.parent.obj['debug']
198-
)
148+
# Process all .po files in the provided directory
149+
translation_files = [f for f in os.listdir(pofile_dir) if
150+
os.path.isfile((os.path.join(pofile_dir, f))) and
151+
f.endswith(".po")]
199152

200-
translation_file = "%s-%s.yaml" % (
201-
ctx.parent.obj['zanata_translation_document'],
202-
ctx.parent.obj['branch'])
153+
catalogs = dict()
154+
for f in translation_files:
155+
with open(f, 'r') as infile:
156+
catalog = pofile.read_po(infile)
157+
catalogs[catalog.locale_identifier] = catalog
203158

204-
Modulemd.dump(sorted(translations), translation_file)
159+
translations = get_modulemd_translations_from_catalog_dict(
160+
catalogs)
205161

206-
print("Wrote modulemd-translations YAML to %s" % translation_file)
162+
if ctx.parent.obj['debug']:
163+
for translation in translations:
164+
print(translation.dumps())
207165

208166

209167
if __name__ == "__main__":

0 commit comments

Comments
 (0)