Source code for fluent.runtime.fallback
# -*- coding: utf-8 -*-
import codecs
import os
import six
[docs]class FluentLocalization(object):
"""
Generic API for Fluent applications.
This handles language fallback, bundle creation and string localization.
It uses the given resource loader to load and parse Fluent data.
"""
def __init__(
self, locales, resource_ids, resource_loader,
use_isolating=False,
bundle_class=None, functions=None,
):
self.locales = locales
self.resource_ids = resource_ids
self.resource_loader = resource_loader
self.use_isolating = use_isolating
if bundle_class is None:
from fluent.runtime import FluentBundle
self.bundle_class = FluentBundle
else:
self.bundle_class = bundle_class
self.functions = functions
self._bundle_cache = []
self._bundle_it = self._iterate_bundles()
def format_value(self, msg_id, args=None):
for bundle in self._bundles():
if not bundle.has_message(msg_id):
continue
msg = bundle.get_message(msg_id)
if not msg.value:
continue
val, errors = bundle.format_pattern(msg.value, args)
return val
return msg_id
def _create_bundle(self, locales):
return self.bundle_class(
locales, functions=self.functions, use_isolating=self.use_isolating
)
def _bundles(self):
bundle_pointer = 0
while True:
if bundle_pointer == len(self._bundle_cache):
try:
self._bundle_cache.append(next(self._bundle_it))
except StopIteration:
return
yield self._bundle_cache[bundle_pointer]
bundle_pointer += 1
def _iterate_bundles(self):
for first_loc in range(0, len(self.locales)):
locs = self.locales[first_loc:]
for resources in self.resource_loader.resources(locs[0], self.resource_ids):
bundle = self._create_bundle(locs)
for resource in resources:
bundle.add_resource(resource)
yield bundle
[docs]class AbstractResourceLoader(object):
"""
Interface to implement for resource loaders.
"""
[docs] def resources(self, locale, resource_ids):
"""
Yield lists of FluentResource objects, corresponding to
each of the resource_ids.
If there are multiple locations, this may yield multiple lists.
If a resource isn't found in any location, yield a partial list,
but don't yield empty lists.
"""
raise NotImplementedError
[docs]class FluentResourceLoader(AbstractResourceLoader):
"""
Resource loader to read Fluent files from disk.
Different locales are in different locations based on locale code.
The locale code should be encoded as `{locale}` in the roots, or in
the resource_ids.
This loader does not support loading resources for one bundle from
different roots.
"""
def __init__(self, roots):
"""
Create a resource loader. The roots may be a string for a single
location on disk, or a list of strings.
"""
self.roots = [roots] if isinstance(roots, six.text_type) else roots
from fluent.runtime import FluentResource
self.Resource = FluentResource
[docs] def resources(self, locale, resource_ids):
for root in self.roots:
resources = []
for resource_id in resource_ids:
path = self.localize_path(os.path.join(root, resource_id), locale)
if not os.path.isfile(path):
continue
content = codecs.open(path, 'r', 'utf-8').read()
resources.append(self.Resource(content))
if resources:
yield resources
def localize_path(self, path, locale):
return path.format(locale=locale)