|
| 1 | +Custom functions |
| 2 | +---------------- |
| 3 | + |
| 4 | +You can add functions to the ones available to FTL authors by passing a |
| 5 | +``functions`` dictionary to the ``FluentBundle`` constructor: |
| 6 | + |
| 7 | +.. code-block:: python |
| 8 | +
|
| 9 | + >>> import platform |
| 10 | + >>> def os_name(): |
| 11 | + ... """Returns linux/mac/windows/other""" |
| 12 | + ... return {'Linux': 'linux', |
| 13 | + ... 'Darwin': 'mac', |
| 14 | + ... 'Windows': 'windows'}.get(platform.system(), 'other') |
| 15 | +
|
| 16 | + >>> bundle = FluentBundle(['en-US'], functions={'OS': os_name}) |
| 17 | + >>> bundle.add_messages(""" |
| 18 | + ... welcome = { OS() -> |
| 19 | + ... [linux] Welcome to Linux |
| 20 | + ... [mac] Welcome to Mac |
| 21 | + ... [windows] Welcome to Windows |
| 22 | + ... *[other] Welcome |
| 23 | + ... } |
| 24 | + ... """) |
| 25 | + >>> print(bundle.format('welcome')[0] |
| 26 | + Welcome to Linux |
| 27 | +
|
| 28 | +These functions can accept positional and keyword arguments, like the ``NUMBER`` |
| 29 | +and ``DATETIME`` builtins. They must accept the following types of objects |
| 30 | +passed as arguments: |
| 31 | +
|
| 32 | +- unicode strings (i.e. ``unicode`` on Python 2, ``str`` on Python 3) |
| 33 | +- ``fluent.runtime.types.FluentType`` subclasses, namely: |
| 34 | +
|
| 35 | + - ``FluentNumber`` - ``int``, ``float`` or ``Decimal`` objects passed in |
| 36 | + externally, or expressed as literals, are wrapped in these. Note that these |
| 37 | + objects also subclass builtin ``int``, ``float`` or ``Decimal``, so can be |
| 38 | + used as numbers in the normal way. |
| 39 | + - ``FluentDateType`` - ``date`` or ``datetime`` objects passed in are wrapped in |
| 40 | + these. Again, these classes also subclass ``date`` or ``datetime``, and can |
| 41 | + be used as such. |
| 42 | + - ``FluentNone`` - in error conditions, such as a message referring to an |
| 43 | + argument that hasn't been passed in, objects of this type are passed in. |
| 44 | +
|
| 45 | +Custom functions should not throw errors, but return ``FluentNone`` instances to |
| 46 | +indicate an error or missing data. Otherwise they should return unicode strings, |
| 47 | +or instances of a ``FluentType`` subclass as above. Returned numbers and |
| 48 | +datetimes should be converted to ``FluentNumber`` or ``FluentDateType`` |
| 49 | +subclasses using ``fluent.types.fluent_number`` and ``fluent.types.fluent_date`` |
| 50 | +respectively. |
| 51 | +
|
| 52 | +The type signatures of custom functions are checked before they are used, to |
| 53 | +ensure the right the number of positional arguments are used, and only available |
| 54 | +keyword arguments are used - otherwise a ``TypeError`` will be appended to the |
| 55 | +``errors`` list. Using ``*args`` or ``**kwargs`` to allow any number of |
| 56 | +positional or keyword arguments is supported, but you should ensure that your |
| 57 | +function actually does allow all positional or keyword arguments. |
| 58 | +
|
| 59 | +If you want to override the detected type signature (for example, to limit the |
| 60 | +arguments that can be used in an FTL file, or to provide a proper signature for |
| 61 | +a function that has a signature using ``*args`` and ``**kwargs`` but is more |
| 62 | +restricted in reality), you can add an ``ftl_arg_spec`` attribute to the |
| 63 | +function. The value should be a two-tuple containing 1) an integer specifying |
| 64 | +the number of positional arguments, and 2) a list of allowed keyword arguments. |
| 65 | +For example, for a custom function ``my_func`` the following will stop the |
| 66 | +``restricted`` keyword argument from being used from FTL files, while allowing |
| 67 | +``allowed``, and will require that a single positional argument is passed: |
| 68 | + |
| 69 | +.. code-block:: python |
| 70 | +
|
| 71 | + def my_func(arg1, allowed=None, restricted=None): |
| 72 | + pass |
| 73 | +
|
| 74 | + my_func.ftl_arg_spec = (1, ['allowed']) |
| 75 | +
|
| 76 | +The Fluent spec allows keyword arguments with hyphens (``-``) in them. |
| 77 | +Since these cannot be used in valid Python keyword arguments, they are |
| 78 | +disallowed by ``fluent.runtime`` and will be filtered out and generate |
| 79 | +errors if you specify such a keyword in ``ftl_arg_spec`` or use one in a |
| 80 | +message. |
0 commit comments