python/moz/l10n/formats/plain_json/serialize.py (50 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 collections.abc import Iterator from json import dumps from typing import Any from ...model import Entry, Message, PatternMessage, Resource def plain_json_serialize( resource: Resource[str] | Resource[Message], trim_comments: bool = False, ) -> Iterator[str]: """ Serialize a resource as a nested JSON object. Comments and metadata are not supported. Yields the entire JSON result as a single string. """ def check(comment: str | None, meta: Any) -> None: if trim_comments: return if comment: raise ValueError("Resource and section comments are not supported") if meta: raise ValueError("Metadata is not supported") def ddict() -> dict[str, Any]: return defaultdict(ddict) check(resource.comment, resource.meta) root = ddict() for section in resource.sections: check(section.comment, section.meta) section_parent = root for part in section.id: section_parent = section_parent[part] for entry in section.entries: if isinstance(entry, Entry): check(entry.comment, entry.meta) if not entry.id: raise ValueError(f"Unsupported empty identifier in {section.id}") msg = entry.value if isinstance(msg, str): value = msg elif isinstance(msg, PatternMessage) and all( isinstance(p, str) for p in msg.pattern ): value = "".join(msg.pattern) # type: ignore[arg-type] else: raise ValueError( f"Unsupported message for {section.id + entry.id}: {msg}" ) parent = section_parent for part in entry.id[:-1]: parent = parent[part] parent[entry.id[-1]] = value else: check(entry.comment, None) yield dumps(root, indent=2, ensure_ascii=False) yield "\n"