Source code for iiisight.language
"""The :class:`LanguageMap` value type for IIIF language maps.
IIIF represents human-readable strings (``label``, ``summary``, metadata
labels/values) as language maps: a mapping of BCP-47 language code to a list of
string values, with the special key ``"none"`` for values with no language.
:class:`LanguageMap` wraps that shape so callers can pull a display string
without hand-indexing ``{"en": ["..."]}``.
"""
from collections.abc import Iterable, Mapping
[docs]
class LanguageMap:
"""An immutable IIIF language map (``lang -> list[str]``).
Construct from a mapping of language code to a list of strings. The ``"none"``
key holds values with no associated language.
"""
__slots__ = ("_values",)
def __init__(self, values: Mapping[str, Iterable[str]] | None = None):
"""Store a defensive copy of ``values`` as ``dict[str, list[str]]``."""
self._values: dict[str, list[str]] = {
lang: list(strings) for lang, strings in (values or {}).items()
}
[docs]
def languages(self) -> list[str]:
"""Return the language codes present, in insertion order."""
return list(self._values)
[docs]
def get(self, language: str) -> list[str]:
"""Return the values for ``language`` (empty list if absent)."""
return list(self._values.get(language, []))
[docs]
def text(self, language: str | None = None, separator: str = " ") -> str:
"""Return a single display string.
Selection order: the requested ``language`` if given and present, else
the no-language ``"none"`` values, else the first language present, else
an empty string. Multiple values for the chosen language are joined with
``separator``.
Args:
language: Preferred language code, or ``None`` for the default order.
separator: Joins multiple values for the chosen language.
Returns:
The chosen values joined into one string.
"""
if language is not None and language in self._values:
chosen = self._values[language]
elif "none" in self._values:
chosen = self._values["none"]
elif self._values:
chosen = next(iter(self._values.values()))
else:
chosen = []
return separator.join(chosen)
def __bool__(self) -> bool:
return bool(self._values)
def __eq__(self, other: object) -> bool:
if isinstance(other, LanguageMap):
return self._values == other._values
return NotImplemented
def __str__(self) -> str:
return self.text()
def __repr__(self) -> str:
return f"LanguageMap({self._values!r})"