You can add functions to the ones available to FTL authors by passing a
functions dictionary to the FluentBundle constructor:
>>> import platform
>>> def os_name():
... """Returns linux/mac/windows/other"""
... return {'Linux': 'linux',
... 'Darwin': 'mac',
... 'Windows': 'windows'}.get(platform.system(), 'other')
>>> bundle = FluentBundle(['en-US'], functions={'OS': os_name})
>>> bundle.add_messages("""
... welcome = { OS() ->
... [linux] Welcome to Linux
... [mac] Welcome to Mac
... [windows] Welcome to Windows
... *[other] Welcome
... }
... """)
>>> print(bundle.format('welcome')[0]
Welcome to LinuxThese functions can accept positional and keyword arguments, like the NUMBER
and DATETIME builtins. They must accept the following types of objects
passed as arguments:
- unicode strings (i.e.
unicodeon Python 2,stron Python 3) fluent.runtime.types.FluentTypesubclasses, namely:FluentNumber-int,floatorDecimalobjects passed in externally, or expressed as literals, are wrapped in these. Note that these objects also subclass builtinint,floatorDecimal, so can be used as numbers in the normal way.FluentDateType-dateordatetimeobjects passed in are wrapped in these. Again, these classes also subclassdateordatetime, and can be used as such.FluentNone- in error conditions, such as a message referring to an argument that hasn't been passed in, objects of this type are passed in.
Custom functions should not throw errors, but return FluentNone instances to
indicate an error or missing data. Otherwise they should return unicode strings,
or instances of a FluentType subclass as above. Returned numbers and
datetimes should be converted to FluentNumber or FluentDateType
subclasses using fluent.types.fluent_number and fluent.types.fluent_date
respectively.
The type signatures of custom functions are checked before they are used, to
ensure the right the number of positional arguments are used, and only available
keyword arguments are used - otherwise a TypeError will be appended to the
errors list. Using *args or **kwargs to allow any number of
positional or keyword arguments is supported, but you should ensure that your
function actually does allow all positional or keyword arguments.
If you want to override the detected type signature (for example, to limit the
arguments that can be used in an FTL file, or to provide a proper signature for
a function that has a signature using *args and **kwargs but is more
restricted in reality), you can add an ftl_arg_spec attribute to the
function. The value should be a two-tuple containing 1) an integer specifying
the number of positional arguments, and 2) a list of allowed keyword arguments.
For example, for a custom function my_func the following will stop the
restricted keyword argument from being used from FTL files, while allowing
allowed, and will require that a single positional argument is passed:
def my_func(arg1, allowed=None, restricted=None):
pass
my_func.ftl_arg_spec = (1, ['allowed'])The Fluent spec allows keyword arguments with hyphens (-) in them. These are
not valid identifiers in Python, so if you need to a custom function to accept
keyword arguments like this, you will have to use **kwargs syntax e.g.:
- def my_func(kwarg1=None, **kwargs):
- kwarg_with_hyphens = kwargs.pop('kwarg-with-hyphens', None) # etc.
my_func.ftl_arg_spec = (0, ['kwarg1', 'kwarg-with-hyphens'])