11import codecs
22import os
3+ from typing import Any , Callable , Dict , Generator , List , TYPE_CHECKING , Type , Union , cast
4+
5+ from fluent .syntax import FluentParser
6+
7+ from .bundle import FluentBundle
8+
9+ if TYPE_CHECKING :
10+ from fluent .syntax .ast import Resource
11+ from .types import FluentType
312
413
514class FluentLocalization :
@@ -9,41 +18,42 @@ class FluentLocalization:
918 This handles language fallback, bundle creation and string localization.
1019 It uses the given resource loader to load and parse Fluent data.
1120 """
21+
1222 def __init__ (
13- self , locales , resource_ids , resource_loader ,
14- use_isolating = False ,
15- bundle_class = None , functions = None ,
23+ self ,
24+ locales : List [str ],
25+ resource_ids : List [str ],
26+ resource_loader : 'AbstractResourceLoader' ,
27+ use_isolating : bool = False ,
28+ bundle_class : Type [FluentBundle ] = FluentBundle ,
29+ functions : Union [Dict [str , Callable [[Any ], 'FluentType' ]], None ] = None ,
1630 ):
1731 self .locales = locales
1832 self .resource_ids = resource_ids
1933 self .resource_loader = resource_loader
2034 self .use_isolating = use_isolating
21- if bundle_class is None :
22- from fluent .runtime import FluentBundle
23- self .bundle_class = FluentBundle
24- else :
25- self .bundle_class = bundle_class
35+ self .bundle_class = bundle_class
2636 self .functions = functions
27- self ._bundle_cache = []
37+ self ._bundle_cache : List [ FluentBundle ] = []
2838 self ._bundle_it = self ._iterate_bundles ()
2939
30- def format_value (self , msg_id , args = None ):
40+ def format_value (self , msg_id : str , args : Union [ Dict [ str , Any ], None ] = None ) -> str :
3141 for bundle in self ._bundles ():
3242 if not bundle .has_message (msg_id ):
3343 continue
3444 msg = bundle .get_message (msg_id )
3545 if not msg .value :
3646 continue
37- val , errors = bundle .format_pattern (msg .value , args )
38- return val
47+ val , _errors = bundle .format_pattern (msg .value , args )
48+ return cast ( str , val ) # Never FluentNone when format_pattern called externally
3949 return msg_id
4050
41- def _create_bundle (self , locales ) :
51+ def _create_bundle (self , locales : List [ str ]) -> FluentBundle :
4252 return self .bundle_class (
4353 locales , functions = self .functions , use_isolating = self .use_isolating
4454 )
4555
46- def _bundles (self ):
56+ def _bundles (self ) -> Generator [ FluentBundle , None , None ] :
4757 bundle_pointer = 0
4858 while True :
4959 if bundle_pointer == len (self ._bundle_cache ):
@@ -54,7 +64,7 @@ def _bundles(self):
5464 yield self ._bundle_cache [bundle_pointer ]
5565 bundle_pointer += 1
5666
57- def _iterate_bundles (self ):
67+ def _iterate_bundles (self ) -> Generator [ FluentBundle , None , None ] :
5868 for first_loc in range (0 , len (self .locales )):
5969 locs = self .locales [first_loc :]
6070 for resources in self .resource_loader .resources (locs [0 ], self .resource_ids ):
@@ -68,7 +78,8 @@ class AbstractResourceLoader:
6878 """
6979 Interface to implement for resource loaders.
7080 """
71- def resources (self , locale , resource_ids ):
81+
82+ def resources (self , locale : str , resource_ids : List [str ]) -> Generator [List ['Resource' ], None , None ]:
7283 """
7384 Yield lists of FluentResource objects, corresponding to
7485 each of the resource_ids.
@@ -89,26 +100,26 @@ class FluentResourceLoader(AbstractResourceLoader):
89100 This loader does not support loading resources for one bundle from
90101 different roots.
91102 """
92- def __init__ (self , roots ):
103+
104+ def __init__ (self , roots : Union [str , List [str ]]):
93105 """
94106 Create a resource loader. The roots may be a string for a single
95107 location on disk, or a list of strings.
96108 """
97109 self .roots = [roots ] if isinstance (roots , str ) else roots
98- from fluent .runtime import FluentResource
99110 self .Resource = FluentResource
100111
101- def resources (self , locale , resource_ids ) :
112+ def resources (self , locale : str , resource_ids : List [ str ]) -> Generator [ List [ 'Resource' ], None , None ] :
102113 for root in self .roots :
103- resources = []
114+ resources : List [ Any ] = []
104115 for resource_id in resource_ids :
105116 path = self .localize_path (os .path .join (root , resource_id ), locale )
106117 if not os .path .isfile (path ):
107118 continue
108119 content = codecs .open (path , 'r' , 'utf-8' ).read ()
109- resources .append (self . Resource (content ))
120+ resources .append (FluentParser (). parse (content ))
110121 if resources :
111122 yield resources
112123
113- def localize_path (self , path , locale ) :
124+ def localize_path (self , path : str , locale : str ) -> str :
114125 return path .format (locale = locale )
0 commit comments