fix(localize): relax error to warning for missing target (#41944)

Some localization workflows want to use the extracted source translation
files directy back in the project as a target translation file.

The extraction process generates files that only contain "source" messages
and not "target" messages. This is actually valid for most translation formats
but currently the Angular localization process expects target translation files
to always contain target messages and will stop with an error in this case.

Now, instead of an error, the translation file loader will log a warning,
and then try to falback to a source message, only erroring if this is also
missing.

Fixes #21690

PR Close #41944
This commit is contained in:
Pete Bacon Darwin 2021-05-04 15:28:41 +01:00 committed by Misko Hevery
parent fdf2e02bff
commit 992c70df59
4 changed files with 1491 additions and 1409 deletions

View File

@ -140,13 +140,23 @@ class XliffTranslationVisitor extends BaseVisitor {
return;
}
// Error if there is no `<target>` child element
const targetMessage = element.children.find(isNamedElement('target'));
let targetMessage = element.children.find(isNamedElement('target'));
if (targetMessage === undefined) {
// Warn if there is no `<target>` child element
addParseDiagnostic(
bundle.diagnostics, element.sourceSpan, 'Missing required <target> element',
ParseErrorLevel.ERROR);
return;
bundle.diagnostics, element.sourceSpan, 'Missing <target> element',
ParseErrorLevel.WARNING);
// Fallback to the `<source>` element if available.
targetMessage = element.children.find(isNamedElement('source'));
if (targetMessage === undefined) {
// Error if there is neither `<target>` nor `<source>`.
addParseDiagnostic(
bundle.diagnostics, element.sourceSpan,
'Missing required element: one of <target> or <source> is required',
ParseErrorLevel.ERROR);
return;
}
}
const {translation, parseErrors, serializeErrors} = serializeTranslationMessage(targetMessage, {

View File

@ -132,12 +132,23 @@ class Xliff2TranslationVisitor extends BaseVisitor {
return;
}
const targetMessage = element.children.find(isNamedElement('target'));
let targetMessage = element.children.find(isNamedElement('target'));
if (targetMessage === undefined) {
// Warn if there is no `<target>` child element
addParseDiagnostic(
bundle.diagnostics, element.sourceSpan, 'Missing required <target> element',
ParseErrorLevel.ERROR);
return;
bundle.diagnostics, element.sourceSpan, 'Missing <target> element',
ParseErrorLevel.WARNING);
// Fallback to the `<source>` element if available.
targetMessage = element.children.find(isNamedElement('source'));
if (targetMessage === undefined) {
// Error if there is neither `<target>` nor `<source>`.
addParseDiagnostic(
bundle.diagnostics, element.sourceSpan,
'Missing required element: one of <target> or <source> is required',
ParseErrorLevel.ERROR);
return;
}
}
const {translation, parseErrors, serializeErrors} = serializeTranslationMessage(targetMessage, {