summaryrefslogtreecommitdiff
path: root/odoo/tools/translate.py
diff options
context:
space:
mode:
authorMartin Trigaux <mat@odoo.com>2019-03-27 15:29:02 +0000
committerMartin Trigaux <mat@odoo.com>2019-06-05 09:44:11 +0000
commiteab46cdca678a87b64e24ee3765eee9274b0df7b (patch)
treedfc8f06bc2aac24ac74a6478361081b481d6f569 /odoo/tools/translate.py
parent632fa044c3c20cdea14b9077bca941f8fc0970b0 (diff)
[IMP] tools: remove custom pofile writer
And create a generic class to handles it, using polib for po files
Diffstat (limited to 'odoo/tools/translate.py')
-rw-r--r--odoo/tools/translate.py230
1 files changed, 119 insertions, 111 deletions
diff --git a/odoo/tools/translate.py b/odoo/tools/translate.py
index a8e13162cb3..555b14fea9a 100644
--- a/odoo/tools/translate.py
+++ b/odoo/tools/translate.py
@@ -607,137 +607,145 @@ class PoFileReader:
_logger.error("malformed po file: unknown occurrence: %s", occurrence)
+def TranslationFileWriter(target, fileformat='po', lang=None, modules=None):
+ """ Iterate over translation file to return Odoo translation entries """
+ if fileformat == 'csv':
+ return CSVFileWriter(target)
+
+ if fileformat == 'po':
+ return PoFileWriter(target, modules=modules, lang=lang)
-# class to handle po files
-class PoFile(object):
+ if fileformat == 'tgz':
+ return TarFileWriter(target, lang=lang)
+
+ raise Exception(_('Unrecognized extension: must be one of '
+ '.csv, .po, or .tgz (received .%s).') % fileformat)
- def __init__(self, buffer):
- # TextIOWrapper closes its underlying buffer on close *and* can't
- self.buffer = codecs.StreamReaderWriter(
- stream=buffer,
- Reader=codecs.getreader('utf-8'),
- Writer=codecs.getwriter('utf-8')
- )
- def write_infos(self, modules):
+class CSVFileWriter:
+ def __init__(self, target):
+ self.writer = pycompat.csv_writer(target, dialect='UNIX')
+ # write header first
+ self.writer.writerow(("module","type","name","res_id","src","value","comments"))
+
+
+ def write_rows(self, rows):
+ for module, type, name, res_id, src, trad, comments in rows:
+ comments = '\n'.join(comments)
+ self.writer.writerow((module, type, name, res_id, src, trad, comments))
+
+
+class PoFileWriter:
+ """ Iterate over po file to return Odoo translation entries """
+ def __init__(self, target, modules, lang):
import odoo.release as release
- self.buffer.write(u"# Translation of %(project)s.\n" \
- "# This file contains the translation of the following modules:\n" \
- "%(modules)s" \
- "#\n" \
- "msgid \"\"\n" \
- "msgstr \"\"\n" \
- '''"Project-Id-Version: %(project)s %(version)s\\n"\n''' \
- '''"Report-Msgid-Bugs-To: \\n"\n''' \
- '''"POT-Creation-Date: %(now)s\\n"\n''' \
- '''"PO-Revision-Date: %(now)s\\n"\n''' \
- '''"Last-Translator: <>\\n"\n''' \
- '''"Language-Team: \\n"\n''' \
- '''"MIME-Version: 1.0\\n"\n''' \
- '''"Content-Type: text/plain; charset=UTF-8\\n"\n''' \
- '''"Content-Transfer-Encoding: \\n"\n''' \
- '''"Plural-Forms: \\n"\n''' \
- "\n"
-
- % { 'project': release.description,
- 'version': release.version,
- 'modules': ''.join("#\t* %s\n" % m for m in modules),
- 'now': datetime.utcnow().strftime('%Y-%m-%d %H:%M')+"+0000",
- }
- )
-
- def write(self, modules, tnrs, source, trad, comments=None):
-
- plurial = len(modules) > 1 and 's' or ''
- self.buffer.write(u"#. module%s: %s\n" % (plurial, ', '.join(modules)))
+ self.buffer = target
+ self.lang = lang
+ self.po = polib.POFile()
+
+ self.po.header = "Translation of %s.\n" \
+ "This file contains the translation of the following modules:\n" \
+ "%s" % (release.description, ''.join("\t* %s\n" % m for m in modules))
+ now = datetime.utcnow().strftime('%Y-%m-%d %H:%M+0000')
+ self.po.metadata = {
+ 'Project-Id-Version': "%s %s" % (release.description, release.version),
+ 'Report-Msgid-Bugs-To': '',
+ 'POT-Creation-Date': now,
+ 'PO-Revision-Date': now,
+ 'Last-Translator': '',
+ 'Language-Team': '',
+ 'MIME-Version': '1.0',
+ 'Content-Type': 'text/plain; charset=UTF-8',
+ 'Content-Transfer-Encoding': '',
+ 'Plural-Forms': '',
+ }
+
+ def write_rows(self, rows):
+ # we now group the translations by source. That means one translation per source.
+ grouped_rows = {}
+ for module, type, name, res_id, src, trad, comments in rows:
+ row = grouped_rows.setdefault(src, {})
+ row.setdefault('modules', set()).add(module)
+ if not row.get('translation') and trad != src:
+ row['translation'] = trad
+ row.setdefault('tnrs', []).append((type, name, res_id))
+ row.setdefault('comments', set()).update(comments)
+
+ for src, row in sorted(grouped_rows.items()):
+ if not self.lang:
+ # translation template, so no translation value
+ row['translation'] = ''
+ elif not row.get('translation'):
+ row['translation'] = ''
+ self.add_entry(row['modules'], row['tnrs'], src, row['translation'], row['comments'])
+
+ # buffer expects bytes
+ self.buffer.write(str(self.po).encode())
+
+ def add_entry(self, modules, tnrs, source, trad, comments=None):
+ entry = polib.POEntry(
+ msgid=source,
+ msgstr=trad,
+ )
+ plural = len(modules) > 1 and 's' or ''
+ entry.comment = "module%s: %s" % (plural, ', '.join(modules))
if comments:
- self.buffer.write(u''.join(('#. %s\n' % c for c in comments)))
+ entry.comment += "\n" + "\n".join(comments)
code = False
for typy, name, res_id in tnrs:
- self.buffer.write(u"#: %s:%s:%s\n" % (typy, name, res_id))
if typy == 'code':
code = True
-
+ if isinstance(res_id, int):
+ # second term of occurrence must be a digit
+ entry.occurrences.append((u"%s:%s" % (typy, name), res_id))
+ else:
+ entry.occurrences.append((u"%s:%s:%s" % (typy, name, res_id), ''))
if code:
- # only strings in python code are python formatted
- self.buffer.write(u"#, python-format\n")
-
- msg = (
- u"msgid %s\n"
- u"msgstr %s\n\n"
- ) % (
- quote(str(source)),
- quote(str(trad))
- )
- self.buffer.write(msg)
+ entry.flags.append("python-format")
+ self.po.append(entry)
+
+
+class TarFileWriter:
+
+ def __init__(self, target, lang):
+ self.tar = tarfile.open(fileobj=target, mode='w|gz')
+ self.lang = lang
+ def write_rows(self, rows):
+ rows_by_module = defaultdict(list)
+ for row in rows:
+ module = row[0]
+ rows_by_module[module].append(row)
+
+ for mod, modrows in rows_by_module.items():
+ with io.BytesIO() as buf:
+ po = PoFileWriter(buf, modules=[mod], lang=self.lang)
+ po.write_rows(modrows)
+ buf.seek(0)
+
+ info = tarfile.TarInfo(
+ join(mod, 'i18n', '{basename}.{ext}'.format(
+ basename=self.lang or mod,
+ ext='po' if self.lang else 'pot',
+ )))
+ # addfile will read <size> bytes from the buffer so
+ # size *must* be set first
+ info.size = len(buf.getvalue())
+
+ self.tar.addfile(info, fileobj=buf)
+
+ self.tar.close()
# Methods to export the translation file
def trans_export(lang, modules, buffer, format, cr):
- def _process(format, modules, rows, buffer, lang):
- if format == 'csv':
- writer = pycompat.csv_writer(buffer, dialect='UNIX')
- # write header first
- writer.writerow(("module","type","name","res_id","src","value","comments"))
- for module, type, name, res_id, src, trad, comments in rows:
- comments = '\n'.join(comments)
- writer.writerow((module, type, name, res_id, src, trad, comments))
-
- elif format == 'po':
- writer = PoFile(buffer)
- writer.write_infos(modules)
-
- # we now group the translations by source. That means one translation per source.
- grouped_rows = {}
- for module, type, name, res_id, src, trad, comments in rows:
- row = grouped_rows.setdefault(src, {})
- row.setdefault('modules', set()).add(module)
- if not row.get('translation') and trad != src:
- row['translation'] = trad
- row.setdefault('tnrs', []).append((type, name, res_id))
- row.setdefault('comments', set()).update(comments)
-
- for src, row in sorted(grouped_rows.items()):
- if not lang:
- # translation template, so no translation value
- row['translation'] = ''
- elif not row.get('translation'):
- row['translation'] = ''
- writer.write(row['modules'], row['tnrs'], src, row['translation'], row['comments'])
-
- elif format == 'tgz':
- rows_by_module = defaultdict(list)
- for row in rows:
- module = row[0]
- rows_by_module[module].append(row)
-
- with tarfile.open(fileobj=buffer, mode='w|gz') as tar:
- for mod, modrows in rows_by_module.items():
- with io.BytesIO() as buf:
- _process('po', [mod], modrows, buf, lang)
- buf.seek(0)
-
- info = tarfile.TarInfo(
- join(mod, 'i18n', '{basename}.{ext}'.format(
- basename=lang or mod,
- ext='po' if lang else 'pot',
- )))
- # addfile will read <size> bytes from the buffer so
- # size *must* be set first
- info.size = len(buf.getvalue())
-
- tar.addfile(info, fileobj=buf)
- else:
- raise Exception(_('Unrecognized extension: must be one of '
- '.csv, .po, or .tgz (received .%s).') % format)
-
translations = trans_generate(lang, modules, cr)
modules = set(t[0] for t in translations)
- _process(format, modules, translations, buffer, lang)
+ writer = TranslationFileWriter(buffer, fileformat=format, lang=lang, modules=modules)
+ writer.write_rows(translations)
del translations