python/moz/l10n/message/from_json.py (86 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.abc import Mapping from typing import Any, Literal from ..model import ( CatchallKey, Expression, Markup, Message, Pattern, PatternMessage, SelectMessage, VariableRef, ) def message_from_json(json: list[Any] | dict[str, Any]) -> Message: """ Marshal the JSON output of `moz.l10n.message.to_json()` back into a parsed `moz.l10n.message.data.Message`. May raise `MF2ValidationError`. """ if isinstance(json, Mapping) and "sel" in json: return SelectMessage( declarations={ name: _expression_from_json(value) for name, value in json["decl"].items() }, selectors=tuple(VariableRef(sel) for sel in json["sel"]), variants={ tuple( key if isinstance(key, str) else CatchallKey(key["*"] or None) for key in variant["keys"] ): _pattern_from_json(variant["pat"]) for variant in json["alt"] }, ) else: declarations = {} if isinstance(json, Mapping): if "decl" in json: declarations = { name: _expression_from_json(value) for name, value in json["decl"].items() } pattern = _pattern_from_json(json["msg"]) else: pattern = _pattern_from_json(json) return PatternMessage(pattern, declarations) def _pattern_from_json(json: list[str | dict[str, Any]]) -> Pattern: return [ part if isinstance(part, str) else _expression_from_json(part) if "_" in part or "$" in part or "fn" in part else _markup_from_json(part) for part in json ] def _expression_from_json(json: dict[str, Any]) -> Expression: if "_" in json: arg = json["_"] elif "$" in json: arg = VariableRef(json["$"]) else: arg = None function = json.get("fn", None) options = ( _options_from_json(json["opt"]) if function is not None and "opt" in json else {} ) return Expression(arg, function, options, json.get("attr", {})) def _markup_from_json(json: dict[str, Any]) -> Markup: kind: Literal["open", "standalone", "close"] if "open" in json: kind = "open" name = json["open"] elif "close" in json: kind = "close" name = json["close"] else: kind = "standalone" name = json["elem"] return Markup( kind, name, _options_from_json(json.get("opt", {})), json.get("attr", {}), ) def _options_from_json(json: dict[str, Any]) -> dict[str, str | VariableRef]: return { name: value if isinstance(value, str) else VariableRef(value["$"]) for name, value in json.items() }