+++ /dev/null
-#!/usr/bin/perl
-use XML::LibXML;
-# ------------------------------------------------------------
-# The xliff2po and po2xliff crosswalk results in message IDs
-# getting stored in an unexpected location as far as Angular is
-# concerned.
-#
-# E.g.
-#
-# <trans-unit xml:space="preserve" id="52" approved="no">
-# <source>Sort Priority</source>
-# <target state="needs-translation">Sort Priority</target>
-# <context-group name="po-reference" purpose="location">
-# <context context-type="sourcefile">1f93d86f7ad773b5f4232b60fff10567179f28f4</context>
-# </context-group>
-# </trans-unit>
-#
-# Angular expaect the trans-unit id attribute to match the "sourcefile"
-# hash from the context group. This script makes that happen.
-# Result is:
-#
-# <trans-unit xml:space="preserve" id="1f93d86f7ad773b5f4232b60fff10567179f28f4" approved="no">
-# <source>Sort Priority</source>
-# <target state="needs-translation">Sort Priority</target>
-# <context-group name="po-reference" purpose="location">
-# <context context-type="sourcefile">1f93d86f7ad773b5f4232b60fff10567179f28f4</context>
-# </context-group>
-# </trans-unit>
-#
-# NOTES:
-# npm run build-translations
-# xliff2po -i src/locale/messages.fr-CA.xlf -o src/locale/messages.fr-CA.po
-# # add translations to .po file ...
-# po2xliff -i src/locale/messages.fr-CA.po -o src/locale/messages.fr-CA.from-PO.xlf
-# perl src/locale/fix-po2xliff.pl src/locale/messages.fr-CA.from-PO.xlf src/locale/messages.fr-CA.xlf
-# ng build --configuration=production-fr-CA ...
-# ------------------------------------------------------------
-
-sub usage {
- print <<DOCS;
- Synopsis:
-
- $0 messages.fr-CA.from-PO.xlf messages.fr-CA.xlf
-
- 1. First param is input file.
- 2. Second param is output file. Defaults to STDOUT.
-DOCS
- exit(0);
-}
-
-# Returns the first element by tag name that's a child of $node.
-sub gbn {
- my ($node, $name) = @_;
- return $node->getElementsByTagName($name)->[0];
-}
-
-my $infile = shift;
-my $outfile = shift;
-
-usage() unless $infile;
-
-my $doc = XML::LibXML->new->parse_file($infile);
-
-my $body = gbn(gbn($doc->documentElement, 'file'), 'body');
-
-for my $trans ($body->getElementsByTagName('trans-unit')) {
-
- my $source = gbn($trans, 'source');
- my $target = gbn($trans, 'target');
- my $context_group = gbn($trans, 'context-group');
- next unless $context_group;
-
- my $context = gbn($context_group, 'context');
- my $msg_id = $context->textContent;
- $trans->setAttribute('id', $msg_id);
-}
-
-if ($outfile) {
- open OUTFILE, '>', $outfile;
- print OUTFILE $doc->toString(1);
-} else {
- print $doc->toString(1) . "\n";
-}
-
-
-
-
-
--- /dev/null
+#!/usr/bin/perl
+use strict;
+use warnings;
+use XML::LibXML;
+# ---------------------------------------------------------------------
+# The xliff2po -> po2xliff round trip results in files Angular is
+# not able to use for localization. The message ID / context data
+# is out of sorts.
+# This script extracts translations from the round-tripped xliff file
+# and merges them back into the original Angular-approved xliff file.
+# ---------------------------------------------------------------------
+
+sub usage {
+ print <<DOCS;
+ Synopsis
+ $0 messages.fr-CA.from-PO.xlf messages.fr-CA.xlf
+
+ messages.fr-CA.from-PO.xlf is the result of a round trip of:
+
+ xliff2po -i messages.fr-CA.xlf -o messages.fr-CA.po
+ # translations applied to .po file...
+ po2xliff -i messages.fr-CA.po -o messages.fr-CA.from-PO.xlf
+DOCS
+ exit(0);
+}
+
+my $xlf_source = shift;
+my $xlf_target = shift;
+my %translations;
+
+usage() unless $xlf_source && $xlf_target;
+
+# Returns the first element by tag name that's a child of $node.
+sub gbn {
+ my ($node, $name) = @_;
+ return $node->getElementsByTagName($name)->[0];
+}
+
+# Create a map of message-id to translated strings.
+# In the round-tripped file, the message ID is stored as file context data.
+sub extract_source_translations {
+
+ my $doc = XML::LibXML->new->parse_file($xlf_source);
+
+ my $body = gbn(gbn($doc->documentElement, 'file'), 'body');
+
+ for my $trans ($body->getElementsByTagName('trans-unit')) {
+
+ my $source = gbn($trans, 'source');
+ my $target = gbn($trans, 'target');
+
+ # No translation, nothing to merge;
+ next if $source->textContent eq $target->textContent;
+
+ my $context_group = gbn($trans, 'context-group');
+ next unless $context_group;
+
+ my $context = gbn($context_group, 'context');
+ my $msg_id = $context->textContent;
+ $translations{$msg_id} = $target->textContent;
+ }
+}
+
+# Merged strings extracted above into the xliff by matching on message id.
+sub merge_target_translations {
+
+ my $doc = XML::LibXML->new->parse_file($xlf_target);
+
+ my $body = gbn(gbn($doc->documentElement, 'file'), 'body');
+
+ for my $trans ($body->getElementsByTagName('trans-unit')) {
+ my $msg_id = $trans->getAttribute('id');
+
+ my $translation = $translations{$msg_id};
+
+ next unless $translation;
+
+ my $source = gbn($trans, 'source');
+ my $target = gbn($trans, 'target');
+
+ # print "Merging translation [$msg_id] ".
+ # $source->textContent . " : $translation\n";
+
+ $target->removeChildNodes();
+ $target->appendTextNode($translation);
+ }
+
+ open TARGET, '>', $xlf_target
+ or die "Cannot open for writing: $xlf_target : $!\n";
+
+ print TARGET $doc->toString(1);
+ close TARGET;
+}
+
+extract_source_translations();
+merge_target_translations();
+