"""
Internationalization (i18n) utilities for OAuth Authorization pages.
Supports English (en) and Persian/Farsi (fa) languages.
Language is auto-detected from Accept-Language header or query parameter.
"""
# Translation dictionary for OAuth authorization pages
TRANSLATIONS: dict[str, dict[str, str]] = {
"en": {
# Page title
"page_title": "Authorization Required - MCP Hub",
# Header section
"auth_required": "Authorization Required",
"wants_access": "{client_name} wants to access your MCP Hub",
# Client information
"client_info": "Client Information",
"client_id_label": "Client ID:",
"redirect_uri_label": "Redirect URI:",
# Permissions section
"requested_permissions": "Requested Permissions:",
"no_permissions": "No specific permissions requested",
# Form section
"enter_api_key": "Enter your API Key to authorize",
"api_key_placeholder": "cmp_xxxxxxxxxxxxxxxx",
"api_key_note": "Your API key will be validated and used to grant permissions to this application.",
# Buttons
"approve": "Authorize",
"deny": "Deny",
# Security notice
"security_note": "Security Note:",
"security_message": "Only authorize applications you trust. The OAuth token will inherit the permissions from your API key.",
# Error page
"error_title": "Authorization Error - MCP Hub",
"auth_error": "Authorization Error",
"unable_to_complete": "Unable to complete the authorization request",
"error_code": "Error Code:",
"error_description": "Description:",
"common_solutions": "Common Solutions:",
"solution_1": "Verify your API key is correct and active",
"solution_2": "Check that the client application is properly configured",
"solution_3": "Ensure the redirect URI matches the registered URI",
"return_to_app": "Return to Application",
"close_window": "Close Window",
"need_help": "Need help? Check the",
"documentation": "documentation",
# Footer
"secured_with": "This connection is secured with OAuth 2.1 + PKCE",
},
"fa": {
# Page title
"page_title": "احراز هویت مورد نیاز - MCP Hub",
# Header section
"auth_required": "احراز هویت مورد نیاز",
"wants_access": "{client_name} میخواهد به MCP Hub شما دسترسی داشته باشد",
# Client information
"client_info": "اطلاعات برنامه",
"client_id_label": "شناسه برنامه:",
"redirect_uri_label": "آدرس بازگشت:",
# Permissions section
"requested_permissions": "دسترسیهای درخواستی:",
"no_permissions": "دسترسی خاصی درخواست نشده",
# Form section
"enter_api_key": "API Key خود را برای احراز هویت وارد کنید",
"api_key_placeholder": "cmp_xxxxxxxxxxxxxxxx",
"api_key_note": "API Key شما اعتبارسنجی شده و برای اعطای دسترسی به این برنامه استفاده خواهد شد.",
# Buttons
"approve": "تایید",
"deny": "رد",
# Security notice
"security_note": "نکته امنیتی:",
"security_message": "فقط برنامههایی را که به آنها اعتماد دارید تایید کنید. توکن OAuth دسترسیهای API Key شما را به ارث خواهد برد.",
# Error page
"error_title": "خطای احراز هویت - MCP Hub",
"auth_error": "خطای احراز هویت",
"unable_to_complete": "امکان تکمیل درخواست احراز هویت وجود ندارد",
"error_code": "کد خطا:",
"error_description": "توضیحات:",
"common_solutions": "راهحلهای رایج:",
"solution_1": "اطمینان حاصل کنید که API Key شما صحیح و فعال است",
"solution_2": "بررسی کنید که برنامه به درستی پیکربندی شده است",
"solution_3": "اطمینان حاصل کنید که آدرس بازگشت با آدرس ثبتشده مطابقت دارد",
"return_to_app": "بازگشت به برنامه",
"close_window": "بستن پنجره",
"need_help": "نیاز به کمک دارید؟",
"documentation": "مستندات",
# Footer
"secured_with": "این اتصال با OAuth 2.1 + PKCE امن شده است",
},
}
def detect_language(accept_language: str | None = None, query_lang: str | None = None) -> str:
"""
Detect user's preferred language from Accept-Language header or query parameter.
Args:
accept_language: Accept-Language header value (e.g., "en-US,en;q=0.9,fa;q=0.8")
query_lang: Explicit language parameter from query string (takes priority)
Returns:
Language code: "en" or "fa"
"""
# Priority 1: Explicit query parameter
if query_lang:
lang = query_lang.lower().strip()
if lang in ["fa", "persian", "farsi"]:
return "fa"
if lang in ["en", "english"]:
return "en"
# Priority 2: Accept-Language header
if accept_language:
# Parse Accept-Language header
# Format: "en-US,en;q=0.9,fa;q=0.8,fa-IR;q=0.7"
languages = []
for lang_entry in accept_language.split(","):
# Extract language code (ignore quality value)
lang = lang_entry.split(";")[0].strip().lower()
languages.append(lang)
# Check for Persian/Farsi
for lang in languages:
if lang.startswith("fa"): # fa, fa-IR, fa-AF
return "fa"
# Check for English
for lang in languages:
if lang.startswith("en"): # en, en-US, en-GB
return "en"
# Default: English
return "en"
def get_translation(lang: str, key: str, **kwargs) -> str:
"""
Get translated string for the given language and key.
Args:
lang: Language code ("en" or "fa")
key: Translation key
**kwargs: Format arguments for string interpolation
Returns:
Translated string with format arguments applied
Example:
>>> get_translation("en", "wants_access", client_name="ChatGPT")
'ChatGPT wants to access your MCP Hub'
>>> get_translation("fa", "wants_access", client_name="ChatGPT")
'ChatGPT میخواهد به MCP Hub شما دسترسی داشته باشد'
"""
# Get language dictionary (fallback to English)
lang_dict = TRANSLATIONS.get(lang, TRANSLATIONS["en"])
# Get translation (fallback to key itself)
text = lang_dict.get(key, key)
# Apply format arguments if provided
if kwargs:
try:
return text.format(**kwargs)
except (KeyError, ValueError):
# If formatting fails, return raw text
return text
return text
def get_all_translations(lang: str) -> dict[str, str]:
"""
Get all translations for a language as a dictionary.
Useful for passing to templates.
Args:
lang: Language code ("en" or "fa")
Returns:
Dictionary of all translations for the language
"""
return TRANSLATIONS.get(lang, TRANSLATIONS["en"])
def get_language_name(lang: str) -> str:
"""
Get human-readable language name.
Args:
lang: Language code
Returns:
Language name in its native form
"""
names = {"en": "English", "fa": "فارسی"}
return names.get(lang, "English")