i18n Python scripts: add script fg-merge-xliff-into-xliff

This script is designed for the following use case:

Suppose a translator has been working on a particular translation file,
and meanwhile the official XLIFF file for this translation has been
updated in FGData (new translatable strings added, obsolete strings
marked or removed, etc.). In such a case, 'fg-merge-xliff-into-xliff'
can be used to merge the translator's work into the official XLIFF
translation file. Essentially, this means that for all strings that have
the same source text, plural status, number of plural forms and of
course target language, the target texts, "approved" status and
translator comments will be taken from the first file passed in the
following command:

  fg-merge-xliff-into-xliff TRANSLATOR_FILE PROJECT_FILE

Used like this, PROJECT_FILE will be updated with data from
TRANSLATOR_FILE. If you don't want to modify PROJECT_FILE, use the -o
(--output) option. If '-' is passed as argument to this option, then the
result is written to the standard output.
This commit is contained in:
Florent Rougon
2017-09-17 16:17:15 +02:00
parent 54d6196698
commit 7142621966
3 changed files with 276 additions and 8 deletions

View File

@@ -746,6 +746,110 @@ class Translation:
.format(lang=self.targetLanguage, cat=cat))
del self[cat]
# Helper method for mergeNonMasterTranslForCategory()
def _mergeNonMasterTranslForCategory_CheckMatchingParams(
self, cat, tid, srcTu, logger):
translUnit = self.translations[cat][tid]
if srcTu.targetLanguage != translUnit.targetLanguage:
logger.warning(
"ignoring translatable string '{id}', because the target "
"languages don't match between the two translations"
.format(id=tid))
return False
if srcTu.sourceText != translUnit.sourceText:
logger.warning(
"ignoring translatable string '{id}', because the source "
"texts differ between the two translations"
.format(id=tid))
return False
if len(srcTu.targetTexts) != len(translUnit.targetTexts):
logger.warning(
"ignoring translatable string '{id}', because the lists "
"of target texts (= number of singular + plural forms) differ "
"between the two translations".format(id=tid))
return False
if srcTu.isPlural != translUnit.isPlural:
logger.warning(
"ignoring translatable string '{id}', because the plural "
"statuses don't match".format(id=tid))
return False
return True
def mergeNonMasterTranslForCategory(self, srcTransl, cat,
logger=dummyLogger):
"""Merge a non-master Translation into 'self' for category 'cat'.
See mergeNonMasterTransl()'s docstring for more info.
"""
if cat not in srcTransl:
return # nothing to merge in this category
elif cat not in self:
raise BadAPIUse(
"cowardly refusing to create category {!r} in the destination "
"translation for an XLIFF-to-XLIFF merge operation "
"(new categories should be first added to the master "
"translation, then merged into each XLIFF translation file)"
.format(cat))
if srcTransl.targetLanguage != self.targetLanguage:
raise BadAPIUse(
"cowardly refusing to merge two XLIFF files with different "
"target languages")
thisCatTranslations = self.translations[cat]
idsSet = { str(tid) for tid in thisCatTranslations.keys() }
for tid, srcTu in srcTransl.translations[cat].items():
if str(tid) not in idsSet:
logger.warning(
"translatable string '{id}' not found in the "
"destination translation during an XLIFF-to-XLIFF merge "
"operation. The string will be ignored, because new "
"translatable strings must be brought by the default "
"translation.".format(id=tid))
continue
# If some parameters don't match (sourceText, isPlural...), the
# translation in 'srcTu' is probably outdated, so don't use it.
elif not self._mergeNonMasterTranslForCategory_CheckMatchingParams(
cat, tid, srcTu, logger):
continue
else:
translUnit = thisCatTranslations[tid]
translUnit.targetTexts = srcTu.targetTexts[:] # copy
translUnit.approved = srcTu.approved
translUnit.translatorComments = srcTu.translatorComments[:]
def mergeNonMasterTransl(self, srcTransl, logger=dummyLogger):
"""Merge the non-master Translation 'srcTransl' into 'self'.
Contrary to mergeMasterTranslation(), this method doesn't add
new translatable strings to 'self', doesn't mark strings as
obsolete or vanished, nor does it add or remove categories in
'self'. It only updates strings in 'self' from 'srcTransl' when
they:
- already exist in 'self';
- have the same target language, source text, plural status
and number of plural forms in 'self' and in 'srcTransl'.
Expected use case: suppose that a translator is working on a
translation file, and meanwhile the official XLIFF file (for
instance) for this translation is updated in the project
repository (new translatable strings added, obsolete strings
marked or removed, etc.). This method can then be used to merge
the translator work into the project file for all strings for
which it makes sense (source text unchanged, same plural status,
etc.).
"""
for cat in srcTransl:
self.mergeNonMasterTranslForCategory(srcTransl, cat, logger=logger)
def nbPluralForms(self):
return nbPluralFormsForLanguage(self.targetLanguage)