# Released under the MIT License. See LICENSE for details.#"""Locale related functionality."""from__future__importannotationsfromtypingimportTYPE_CHECKING,override,assert_neverfromfunctoolsimportcachefrombacommon.localeimportLocale,LocaleResolvedimport_babasefrombabase._appsubsystemimportAppSubsystemfrombabase._loggingimportapplogifTYPE_CHECKING:fromtypingimportAny,Sequenceimportbabase
[docs]classLocaleSubsystem(AppSubsystem):"""Locale functionality for the app. Access the single shared instance of this class via the :attr:`~babase.App.locale` attr on the :class:`~babase.App` class. """def__init__(self)->None:super().__init__()self._current_locale:Locale|None=None# Calc our default locale based on the locale-tag provided by# the native layer.env=_babase.env()ba_locale=env.get('ba_locale')locale_tag=env.get('locale')ifnotisinstance(ba_locale,str)ornotisinstance(locale_tag,str):applog.warning('Seem to be running in a dummy env; using en-US locale-tag.')ba_locale=''locale_tag='en-US'#: The default locale based on the current runtime environment#: and app capabilities. This locale will be used unless the user#: explicitly overrides it.self.default_locale:Locale=Locale.ENGLISH# If a Locale long-name was provided, try to use that.have_valid_ba_locale=Falseifba_locale:try:self.default_locale=Locale.from_long_value(ba_locale)have_valid_ba_locale=TrueexceptValueError:applog.error('Invalid ba_locale "%s";'' will fall back to using locale tag.',ba_locale,)# Otherwise calc Locale from a tag ('en-US', etc.)ifnothave_valid_ba_locale:self.default_locale=LocaleResolved.from_tag(locale_tag).locale# If we can't properly display this default locale, set it to# English instead.ifnotself.can_display_locale(self.default_locale):self.default_locale=Locale.ENGLISHassertself.can_display_locale(self.default_locale)@overridedefapply_app_config(self)->None:""":meta private:"""assert_babase.in_logic_thread()assertisinstance(_babase.app.config,dict)locale=self.default_locale# Look for a 'Lang' in app-config to override the default. We# expect this to be a Locale long-value such as# 'ChineseTraditional'.lang=_babase.app.config.get('Lang')iflangisnotNone:try:locale=Locale.from_long_value(lang)exceptValueError:applog.error('Invalid Lang "%s"; falling back to default.',lang)# Convert the locale to resolved and back again to make sure# we're loading a currently-supported one (for example this will# convert 'Spanish' to 'SpanishLatinAmerica').locale=locale.resolved.localeself._current_locale=locale_babase.app.lang.setlanguage(locale.long_value,print_change=False,store_to_config=False,ignore_redundant=True,)@propertydefcurrent_locale(self)->Locale:"""The current locale for the app."""ifself._current_localeisNone:raiseRuntimeError('Locale is not set.')returnself._current_locale
[docs]@staticmethod@cachedefcan_display_locale(locale:Locale)->bool:"""Are we able to display the passed locale? Some locales require integration with the OS to display the full range of unicode text, which is not implemented on all platforms. """# pylint: disable=too-many-boolean-expressionscls=LocaleResolvedrlocale=locale.resolved# DO need full unicode.if(rlocaleiscls.CHINESE_TRADITIONALorrlocaleiscls.CHINESE_SIMPLIFIEDorrlocaleiscls.ARABICorrlocaleiscls.HINDIorrlocaleiscls.KOREANorrlocaleiscls.PERSIANorrlocaleiscls.TAMILorrlocaleiscls.THAIorrlocaleiscls.VIETNAMESE):# Return True only if we can display full unicode.return_babase.supports_unicode_display()# Do NOT need full unicode; can always display.if(rlocaleiscls.ENGLISHorrlocaleiscls.PORTUGUESE_PORTUGALorrlocaleiscls.PORTUGUESE_BRAZILorrlocaleiscls.BELARUSSIANorrlocaleiscls.CROATIANorrlocaleiscls.CZECHorrlocaleiscls.DANISHorrlocaleiscls.DUTCHorrlocaleiscls.PIRATE_SPEAKorrlocaleiscls.ESPERANTOorrlocaleiscls.FILIPINOorrlocaleiscls.FRENCHorrlocaleiscls.GERMANorrlocaleiscls.GIBBERISHorrlocaleiscls.GREEKorrlocaleiscls.HUNGARIANorrlocaleiscls.INDONESIANorrlocaleiscls.ITALIANorrlocaleiscls.MALAYorrlocaleiscls.POLISHorrlocaleiscls.ROMANIANorrlocaleiscls.RUSSIANorrlocaleiscls.SERBIANorrlocaleiscls.SPANISH_LATIN_AMERICAorrlocaleiscls.SPANISH_SPAINorrlocaleiscls.SLOVAKorrlocaleiscls.SWEDISHorrlocaleiscls.TURKISHorrlocaleiscls.UKRAINIANorrlocaleiscls.VENETIAN):returnTrue# Make sure we're covering all cases.assert_never(rlocale)
# Docs-generation hack; import some stuff that we likely only forward-declared# in our actual source code so that docs tools can find it.fromtypingimport(Coroutine,Any,Literal,Callable,Generator,Awaitable,Sequence,Self)importasynciofromconcurrent.futuresimportFuturefrompathlibimportPathfromenumimportEnum