diff --git a/toolforge_i18n/language_info.py b/toolforge_i18n/language_info.py index 989b2e4..9dcc0f1 100644 --- a/toolforge_i18n/language_info.py +++ b/toolforge_i18n/language_info.py @@ -1,61 +1,77 @@ import mwapi # type: ignore import requests -from typing import Optional +from typing import Literal, Optional user_agent: Optional[str] = None """The user agent to use for API requests. If this is not set, the module will attempt to use a user agent previously set by toolforge::set_user_agent(), and otherwise fail. Usually, you should call toolforge::set_user_agent() during early initialization of your tool; otherwise, you may set the user_agent here explicitly. """ def _user_agent() -> str: if user_agent is not None: return user_agent toolforge_user_agent = requests.utils.default_user_agent() if 'toolforge' in toolforge_user_agent: return toolforge_user_agent raise RuntimeError( "Could not determine user agent, " "either call toolforge.set_user_agent() " "or set toolforge_i18n.language_info.user_agent" ) _language_info = None def _load_language_info() -> dict[str, dict]: session = mwapi.Session( 'https://meta.wikimedia.org', user_agent=_user_agent(), ) language_info = {} for response in session.get(continuation=True, action='query', meta='languageinfo', - liprop=['autonym', 'fallbacks'], + liprop=['autonym', 'bcp47', 'dir', 'fallbacks'], formatversion='2'): language_info.update(response['query']['languageinfo']) return language_info def autonym(code: str) -> Optional[str]: """Get the autonym of the given language code, according to MediaWiki.""" global _language_info if _language_info is None: _language_info = _load_language_info() return _language_info.get(code, {}).get('autonym') +def bcp47(code: str) -> str: + """Get the BCP-47 language code of the given MediaWiki language code.""" + global _language_info + if _language_info is None: + _language_info = _load_language_info() + return _language_info.get(code, {}).get('bcp47', code) + + +def directionality(code: str) -> Literal['ltr', 'rtl', 'auto']: + """Get the directionality of the given language code, according to MediaWiki.""" + global _language_info + if _language_info is None: + _language_info = _load_language_info() + return _language_info.get(code, {}).get('dir', 'auto') + + def fallbacks(code: str) -> list[str]: """Get the fallback languages of the given language code, according to MediaWiki.""" global _language_info if _language_info is None: _language_info = _load_language_info() return _language_info.get(code, {}).get('fallbacks', []) diff --git a/toolforge_i18n/test_language_info.py b/toolforge_i18n/test_language_info.py index 931a497..5c9b3ce 100644 --- a/toolforge_i18n/test_language_info.py +++ b/toolforge_i18n/test_language_info.py @@ -1,28 +1,46 @@ import pytest from typing import Optional -from .language_info import autonym, fallbacks +from .language_info import autonym, bcp47, directionality, fallbacks import toolforge_i18n.language_info toolforge_i18n.language_info.user_agent = 'toolforge-i18n test (not published yet; mail@lucaswerkmeister.de)' @pytest.mark.parametrize('code, expected', [ ('en', 'English'), ('de', 'Deutsch'), ('fa', 'فارسی'), ('bn-x-Q6747180', None) ]) def test_autonym(code: str, expected: Optional[str]): assert autonym(code) == expected +@pytest.mark.parametrize('code, expected', [ + ('en', 'en'), + ('simple', 'en-simple'), + ('unknown', 'unknown') +]) +def test_bcp47(code: str, expected: str): + assert bcp47(code) == expected + + +@pytest.mark.parametrize('code, expected', [ + ('en', 'ltr'), + ('fa', 'rtl'), + ('unknown', 'auto') +]) +def test_directionality(code: str, expected: str): + assert directionality(code) == expected + + @pytest.mark.parametrize('code, expected', [ ('en', []), ('de', []), ('de-at', ['de']), ('sh', ['sh-latn', 'sh-cyrl', 'bs', 'sr-el', 'sr-latn', 'hr']), ]) def test_fallbacks(code: str, expected: list[str]): assert fallbacks(code) == expected