python/moz/l10n/resource/l10n_equal.py (48 lines of code) (raw):

# Copyright Mozilla Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations from collections import defaultdict from typing import Any, Dict, List, Set, Tuple, TypeVar from ..model import Entry, Resource, Section _T = TypeVar("_T") _L10nData = List[ Tuple[Tuple[str, ...], str, Dict[str, Set[Any]], _T] ] # id, comment, value def l10n_equal(a: Resource[Any], b: Resource[Any]) -> bool: """ Compares the localization-relevant content (id, comment, metadata, message values) of two resources. Sections with no message entries are ignored, and the order of sections, entries, and metadata is ignored. """ return ( a.format == b.format and a.comment.strip() == b.comment.strip() and l10n_meta(a) == l10n_meta(b) and l10n_sections(a) == l10n_sections(b) ) def l10n_sections(resource: Resource[Any]) -> _L10nData[_L10nData[Any]]: ls = [ (section.id, section.comment.strip(), l10n_meta(section), l10n_entries(section)) for section in resource.sections if any(isinstance(entry, Entry) for entry in section.entries) ] ls.sort() nonempty_idx = next( (idx for idx, (id, comment, meta, _) in enumerate(ls) if id or comment or meta), len(ls), ) if nonempty_idx > 1: # Anonymous sections are considered equivalent first = ls[0] for sd in ls[1:nonempty_idx]: first[3].extend(sd[3]) first[3].sort() del ls[1:nonempty_idx] return ls def l10n_entries(section: Section[Any]) -> _L10nData[Any]: le = [ (entry.id, entry.comment.strip(), l10n_meta(entry), entry.value) for entry in section.entries if isinstance(entry, Entry) ] le.sort() return le def l10n_meta( x: Entry[Any] | Section[Any] | Resource[Any], ) -> dict[str, set[Any]]: md: dict[str, set[Any]] = defaultdict(set) for m in x.meta: md[m.key].add(m.value) return md