|
2 | 2 | from __future__ import unicode_literals |
3 | 3 |
|
4 | 4 | import os |
5 | | -import sys |
6 | 5 | import codecs |
7 | 6 | import logging |
8 | 7 |
|
| 8 | +try: |
| 9 | + from itertools import zip_longest |
| 10 | +except ImportError: |
| 11 | + from itertools import izip_longest as zip_longest |
| 12 | + |
9 | 13 | import fluent.syntax.ast as FTL |
10 | 14 | from fluent.syntax.parser import FluentParser |
11 | 15 | from fluent.syntax.serializer import FluentSerializer |
@@ -202,6 +206,29 @@ def get_source(self, path, key): |
202 | 206 | resource = self.localization_resources[path] |
203 | 207 | return resource.get(key, None) |
204 | 208 |
|
| 209 | + def messages_equal(self, res1, res2): |
| 210 | + """Compare messages of two FTL resources. |
| 211 | +
|
| 212 | + Uses FTL.BaseNode.equals to compare all messages in two FTL resources. |
| 213 | + If the order or number of messages differ, the result is also False. |
| 214 | + """ |
| 215 | + def message_id(message): |
| 216 | + "Return the message's identifer name for sorting purposes." |
| 217 | + return message.id.name |
| 218 | + |
| 219 | + messages1 = sorted( |
| 220 | + (entry for entry in res1.body if isinstance(entry, FTL.Message)), |
| 221 | + key=message_id) |
| 222 | + messages2 = sorted( |
| 223 | + (entry for entry in res2.body if isinstance(entry, FTL.Message)), |
| 224 | + key=message_id) |
| 225 | + for msg1, msg2 in zip_longest(messages1, messages2): |
| 226 | + if msg1 is None or msg2 is None: |
| 227 | + return False |
| 228 | + if not msg1.equals(msg2): |
| 229 | + return False |
| 230 | + return True |
| 231 | + |
205 | 232 | def merge_changeset(self, changeset=None): |
206 | 233 | """Return a generator of FTL ASTs for the changeset. |
207 | 234 |
|
@@ -256,16 +283,14 @@ def in_changeset(ident): |
256 | 283 | self, reference, current, transforms, in_changeset |
257 | 284 | ) |
258 | 285 |
|
259 | | - # Skip this path if the merged snapshot is identical to the current |
260 | | - # state of the localization file. This may happen when: |
| 286 | + # Skip this path if the messages in the merged snapshot are |
| 287 | + # identical to those in the current state of the localization file. |
| 288 | + # This may happen when: |
261 | 289 | # |
262 | 290 | # - none of the transforms is in the changset, or |
263 | 291 | # - all messages which would be migrated by the context's |
264 | 292 | # transforms already exist in the current state. |
265 | | - # |
266 | | - # We compare JSON trees rather then use filtering by `in_changeset` |
267 | | - # to account for translations removed from `reference`. |
268 | | - if snapshot.to_json() == current.to_json(): |
| 293 | + if self.messages_equal(current, snapshot): |
269 | 294 | continue |
270 | 295 |
|
271 | 296 | # Store the merged snapshot on the context so that the next merge |
|
0 commit comments