Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ API Docs: [wd-textify.wmcloud.org/docs](https://wd-textify.wmcloud.org/docs)
| `id` | string | Yes | Comma-separated entity IDs (for example: `Q42` or `Q42,Q2`). |
| `pid` | string | No | Comma-separated property IDs to filter claims (for example: `P31,P279`). |
| `lang` | string | No | Preferred language code (default: `en`). |
| `fallback_lang` | string | No | Fallback language code (default: `en`). |
| `fallback_lang` | string | No | Fallback language code (default: `en`). Use `any` to select the first available language when the requested language is unavailable. |
| `format` | string | No | Output format: `json`, `text`, or `triplet` (default: `json`). |
| `external_ids` | bool | No | Include `external-id` datatype claims (default: `true`). |
| `all_ranks` | bool | No | Include all statement ranks instead of preferred/normal filtering (default: `false`). |
Expand Down
1 change: 1 addition & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ async def get_textified_wd(
- **all_ranks** (bool): If `true`, include preferred, normal, and deprecated statement ranks.
- **qualifiers** (bool): If `true`, include qualifiers for claim values.
- **fallback_lang** (str): Fallback language used when `lang` is unavailable.
Use `any` to select a deterministic available language from the entity.
- **action_api_url** (str): Action API URL
(default: `https://www.wikidata.org/w/api.php`).

Expand Down
21 changes: 16 additions & 5 deletions src/WikibaseLabel.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,18 +368,29 @@ def get_lang_val(data, lang="en", fallback_lang=None):
Args:
data (dict): Label dictionary keyed by language.
lang (str): Preferred language code.
fallback_lang (str | None): Optional fallback language code.
fallback_lang (str | None): Optional fallback language code. Use
``"any"`` to select the first available language when the
requested language is unavailable.

Returns:
str: Selected label text, or an empty string when missing.
"""
label = data.get(lang, data.get("mul", {}))
if fallback_lang and not label:
label = data.get(fallback_lang, {})
if not isinstance(data, dict):
return ""

lang = lang.lower()
fallback_lang = fallback_lang.lower() if fallback_lang else None

label = data.get(lang) or data.get("mul")
if not label and fallback_lang:
if fallback_lang == "any":
label = next((data[key] for key in sorted(data) if data[key]), None)
else:
label = data.get(fallback_lang)

if isinstance(label, str):
return label
return label.get("value", "")
return label.get("value", "") if isinstance(label, dict) else ""

@staticmethod
def get_all_missing_labels_ids(data):
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/test_wikibaselabel.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ def test_get_lang_val_falls_back_to_mul_and_fallback_language():
assert WikibaseLabel.get_lang_val(labels_without_mul, lang="en", fallback_lang="fr") == "Etiquette"


def test_get_lang_val_falls_back_to_any_available_language():
"""It should select a stable available language with the wildcard fallback."""
labels = {
"de": {"value": "Etikett"},
"fr": {"value": "Etiquette"},
}

assert WikibaseLabel.get_lang_val(labels, lang="en", fallback_lang="any") == "Etikett"


def test_get_all_missing_labels_ids_collects_nested_ids():
"""It should collect IDs from nested property, unit, claim, and datavalue branches."""
payload = {
Expand Down
Loading