Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/python/moz_l10n/moz/l10n/migrate/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 6 kB image not shown  

Quelle  utils.py

  Sprache: Python
 

# 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 dataclasses import dataclass, field
from logging import getLogger
from typing import Any, TypeVar, Union

from moz.l10n.model import (
    CatchallKey,
    Entry,
    Expression,
    Id,
    Message,
    Pattern,
    PatternMessage,
    Resource,
    Section,
    SelectMessage,
    VariableRef,
)
from moz.l10n.paths.config import L10nConfigPaths
from moz.l10n.paths.discover import L10nDiscoverPaths
from moz.l10n.resource import parse_resource

log = getLogger(__name__)
M = TypeVar("M", bound=Union[Message, str])


@dataclass
class MigrationContext:
    paths: L10nConfigPaths | L10nDiscoverPaths
    ref_path: str
    locale: str
    parse_options: dict[str, Any]
    target_id: Id = ()

    _prev_ids: list[Id] = field(default_factory=list)
    _resources: dict[str, Resource[Message] | None] = field(default_factory=dict)

    def get_resource(self, ref_path: str) -> Resource[Message] | None:
        if ref_path in self._resources:
            return self._resources[ref_path]
        tgt_path, _ = self.paths.target(ref_path, locale=self.locale)
        try:
            res = parse_resource(tgt_path, **self.parse_options)
        except OSError:
            log.debug(f"Resource not available: {tgt_path}")
            res = None
        except Exception:
            log.debug(f"Parse error: {tgt_path}", exc_info=True)
            res = None
        self._resources[ref_path] = res
        return res

    def pretty_id(self, id: tuple[str, ...]) -> str:
        return f"{'.'.join(id)} in {self.ref_path} for locale {self.locale}"

    def _update(self, id: Id | str) -> None:
        if self.target_id:
            self._prev_ids.append(self.target_id)
        self.target_id = (id,) if isinstance(id, str) else id

    def __str__(self) -> str:
        return self.pretty_id(self.target_id)


def get_entry(res: Resource[M], *id: str) -> Entry[M] | None:
    """
    Get an entry matching `id` from `res`.

    If not found return None
    """
    for section in res.sections:
        if section.id:
            sid_len = len(section.id)
            if section.id != id[:sid_len]:
                continue
            eid = id[sid_len:]
        else:
            eid = id
        entry = next(
            (e for e in section.entries if isinstance(e, Entry) and e.id == eid),
            None,
        )
        if entry is not None:
            return entry
    return None


def get_pattern(
    res: Resource[Message],
    *id: str,
    property: str | None = None,
    default: Pattern | None = None,
    variant: tuple[str | CatchallKey, ...] | str | None = None,
) -> Pattern:
    """
    Get a pattern matching `id`, `property`, and `variant` from `res`.

    If `property` is not set, a pattern from the `id` entry's `.value` is returned.
    Otherwise, a pattern from its `.properties[property]` is returned.

    If the message for `id` and `property` is a SelectMessage,
    either the pattern matching `variant` is returned,
    or (if not found) the fallback pattern is returned.

    If `default` is a Pattern, it is returned if no matching pattern is found.
    Otherwise, a StopIteration exception is raised.
    """
    entry = get_entry(res, *id)
    if entry is None:
        if default is not None:
            return default
        raise StopIteration

    if property is None:
        msg = entry.value
    elif property in entry.properties:
        msg = entry.properties[property]
    else:
        raise StopIteration

    if isinstance(msg, PatternMessage):
        return msg.pattern
    elif isinstance(msg, SelectMessage):
        if isinstance(variant, str):
            variant = (variant,)
        if variant in msg.variants:
            return msg.variants[variant]
        return next(
            pattern
            for keys, pattern in msg.variants.items()
            if all(isinstance(key, CatchallKey) for key in keys)
        )

    raise ValueError(f"Value of {id} entry is not a Message")


def insert_entry_after(
    res: Resource[M],
    entry: Entry[M],
    *src_ids: tuple[str, ...] | str,
) -> None:
    """
    Insert `entry` in `res` after the last entry
    with an `.id` matching one of `src_ids`,
    or if none such are found,
    at the end of the last section matching any of `ids`.

    Note that `entry.id` is expected to include its section id,
    which will be dropped before insertion.

    If no suitable insertion position is found, raises StopIteration.
    """
    id_set = {id if isinstance(id, tuple) else (id,) for id in src_ids}
    last_section: Section[M] | None = None
    for section in reversed(res.sections):
        if section.id:
            sid_len = len(section.id)
            eid_set = {id[sid_len:] for id in id_set if section.id == id[:sid_len]}
            if not eid_set:
                continue
        else:
            sid_len = 0
            eid_set = id_set
        for e_rev_idx, e in enumerate(reversed(section.entries)):
            if isinstance(e, Entry) and e.id in eid_set:
                if sid_len:
                    entry.id = entry.id[sid_len:]
                section.entries.insert(len(section.entries) - e_rev_idx, entry)
                return
        last_section = section
    if last_section is None:
        raise StopIteration
    else:
        if last_section.id:
            entry.id = entry.id[len(last_section.id) :]
        last_section.entries.append(entry)


def plural_message(
    var_name: str,
    *,
    zero: Pattern | None = None,
    one: Pattern | None = None,
    two: Pattern | None = None,
    few: Pattern | None = None,
    many: Pattern | None = None,
    other: Pattern,
) -> SelectMessage:
    """
    Construct a SelectMessage using `var_name` to determine the plural category,
    with the given variants.

    By convention, use the following as `var_name`:

    - `"n"for Gettext plurals
    - `"quantity"for Android strings.
    """
    raw_variants: list[tuple[str | CatchallKey, Pattern | None]] = [
        ("zero", zero),
        ("one", one),
        ("two", two),
        ("few", few),
        ("many", many),
        (CatchallKey("other"), other),
    ]
    return SelectMessage(
        declarations={var_name: Expression(VariableRef(var_name), "number")},
        selectors=(VariableRef(var_name),),
        variants={
            (key,): pattern for key, pattern in raw_variants if pattern is not None
        },
    )

Messung V0.5 in Prozent
C=99 H=100 G=99

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-08-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.