@@ -44,7 +44,6 @@ python-fluent consists of two packages:
4444
4545
4646* ` fluent.runtime ` - methods for generating translations from FTL files.
47- Documentation below.
4847
4948 To install:
5049
@@ -59,221 +58,8 @@ PyPI also contains an old `fluent` package which is an older version of just
5958Usage
6059-----
6160
62- To generate translations using the `` fluent.runtime `` package, you start with
63- the ` FluentBundle ` class:
64-
65- >>> from fluent.runtime import FluentBundle
66-
67- You pass a list of locales to the constructor - the first being the desired
68- locale, with fallbacks after that:
69-
70- >>> bundle = FluentBundle(["en-US"])
71-
72-
73- You must then add messages. These would normally come from a ` .ftl ` file stored
74- on disk, here we will just add them directly:
75-
76- >>> bundle.add_messages("""
77- ... welcome = Welcome to this great app!
78- ... greet-by-name = Hello, { $name }!
79- ... """)
80-
81- To generate translations, use the ` format ` method, passing a message ID and an
82- optional dictionary of substitution parameters. If the the message ID is not
83- found, a ` LookupError ` is raised. Otherwise, as per the Fluent philosophy, the
84- implementation tries hard to recover from any formatting errors and generate the
85- most human readable representation of the value. The ` format ` method therefore
86- returns a tuple containing ` (translated string, errors) ` , as below.
87-
88- >>> translated, errs = bundle.format('welcome')
89- >>> translated
90- "Welcome to this great app!"
91- >>> errs
92- []
93-
94- >>> translated, errs = bundle.format('greet-by-name', {'name': 'Jane'})
95- >>> translated
96- 'Hello, \u2068Jane\u2069!'
97-
98- >>> translated, errs = bundle.format('greet-by-name', {})
99- >>> translated
100- 'Hello, \u2068name\u2069!'
101- >>> errs
102- [FluentReferenceError('Unknown external: name')]
103-
104- You will notice the extra characters ` \u2068 ` and ` \u2069 ` in the output. These
105- are Unicode bidi isolation characters that help to ensure that the interpolated
106- strings are handled correctly in the situation where the text direction of the
107- substitution might not match the text direction of the localized text. These
108- characters can be disabled if you are sure that is not possible for your app by
109- passing ` use_isolating=False ` to the ` FluentBundle ` constructor.
110-
111- Python 2
112- --------
113-
114- The above examples assume Python 3. Since Fluent uses unicode everywhere
115- internally (and doesn't accept bytestrings), if you are using Python 2 you will
116- need to make adjustments to the above example code. Either add ` u ` unicode
117- literal markers to strings or add this at the top of the module or the start of
118- your repl session:
119-
120- from __future__ import unicode_literals
121-
122-
123- Numbers
124- -------
125-
126- When rendering translations, Fluent passes any numeric arguments (int or float)
127- through locale-aware formatting functions:
128-
129- >>> bundle.add_messages("show-total-points = You have { $points } points.")
130- >>> val, errs = bundle.format("show-total-points", {'points': 1234567})
131- >>> val
132- 'You have 1,234,567 points.'
133-
134-
135- You can specify your own formatting options on the arguments passed in by
136- wrapping your numeric arguments with ` fluent.runtime.types.fluent_number ` :
137-
138- >>> from fluent.runtime.types import fluent_number
139- >>> points = fluent_number(1234567, useGrouping=False)
140- >>> bundle.format("show-total-points", {'points': points})[0]
141- 'You have 1234567 points.'
142-
143- >>> amount = fluent_number(1234.56, style="currency", currency="USD")
144- >>> bundle.add_messages("your-balance = Your balance is { $amount }")
145- >>> bundle.format("your-balance", {'amount': amount})[0]
146- 'Your balance is $1,234.56'
147-
148- Thee options available are defined in the Fluent spec for
149- [ NUMBER] ( https://projectfluent.org/fluent/guide/functions.html#number ) . Some of
150- these options can also be defined in the FTL files, as described in the Fluent
151- spec, and the options will be merged.
152-
153- Date and time
154- -------------
155-
156- Python ` datetime.datetime ` and ` datetime.date ` objects are also passed through
157- locale aware functions:
158-
159- >>> from datetime import date
160- >>> bundle.add_messages("today-is = Today is { $today }")
161- >>> val, errs = bundle.format("today-is", {"today": date.today() })
162- >>> val
163- 'Today is Jun 16, 2018'
164-
165- You can explicitly call the ` DATETIME ` builtin to specify options:
166-
167- >>> bundle.add_messages('today-is = Today is { DATETIME($today, dateStyle: "short") }')
168-
169- See the [ DATETIME
170- docs] ( https://projectfluent.org/fluent/guide/functions.html#datetime ) . However,
171- currently the only supported options to ` DATETIME ` are:
172-
173- * ` timeZone `
174- * ` dateStyle ` and ` timeStyle ` which are [ proposed
175- additions] ( https://github.com/tc39/proposal-ecma402-datetime-style ) to the ECMA i18n spec.
176-
177- To specify options from Python code, use ` fluent.runtime.types.fluent_date ` :
178-
179- >>> from fluent.runtime.types import fluent_date
180- >>> today = date.today()
181- >>> short_today = fluent_date(today, dateStyle='short')
182- >>> val, errs = bundle.format("today-is", {"today": short_today })
183- >>> val
184- 'Today is 6/17/18'
185-
186- You can also specify timezone for displaying ` datetime ` objects in two ways:
187-
188- * Create timezone aware ` datetime ` objects, and pass these to the ` format ` call
189- e.g.:
190-
191- >>> import pytz
192- >>> from datetime import datetime
193- >>> utcnow = datime.utcnow().replace(tzinfo=pytz.utc)
194- >>> moscow_timezone = pytz.timezone('Europe/Moscow')
195- >>> now_in_moscow = utcnow.astimezone(moscow_timezone)
196-
197- * Or, use timezone naive ` datetime ` objects, or ones with a UTC timezone, and
198- pass the ` timeZone ` argument to ` fluent_date ` as a string:
199-
200- >>> utcnow = datetime.utcnow()
201- >>> utcnow
202- datetime.datetime(2018, 6, 17, 12, 15, 5, 677597)
203-
204- >>> bundle.add_messages("now-is = Now is { $now }")
205- >>> val, errs = bundle.format("now-is",
206- ... {"now": fluent_date(utcnow,
207- ... timeZone="Europe/Moscow",
208- ... dateStyle="medium",
209- ... timeStyle="medium")})
210- >>> val
211- 'Now is Jun 17, 2018, 3:15:05 PM'
212-
213-
214- Custom functions
215- ----------------
216-
217- You can add functions to the ones available to FTL authors by passing
218- a ` functions ` dictionary to the ` FluentBundle ` constructor:
219-
220-
221- >>> import platform
222- >>> def os_name():
223- ... """Returns linux/mac/windows/other"""
224- ... return {'Linux': 'linux',
225- ... 'Darwin': 'mac',
226- ... 'Windows': 'windows'}.get(platform.system(), 'other')
227-
228- >>> bundle = FluentBundle(['en-US'], functions={'OS': os_name})
229- >>> bundle.add_messages("""
230- ... welcome = { OS() ->
231- ... [linux] Welcome to Linux
232- ... [mac] Welcome to Mac
233- ... [windows] Welcome to Windows
234- ... *[other] Welcome
235- ... }
236- ... """)
237- >>> print(bundle.format('welcome')[0]
238- Welcome to Linux
239-
240- These functions can accept positioal and keyword arguments (like the ` NUMBER `
241- and ` DATETIME ` builtins), and in this case must accept the following types of
242- arguments:
243-
244- * unicode strings (i.e. ` unicode ` on Python 2, ` str ` on Python 3)
245- * ` fluent.runtime.types.FluentType ` subclasses, namely:
246- * ` FluentNumber ` - ` int ` , ` float ` or ` Decimal ` objects passed in externally,
247- or expressed as literals, are wrapped in these. Note that these objects also
248- subclass builtin ` int ` , ` float ` or ` Decimal ` , so can be used as numbers in
249- the normal way.
250- * ` FluentDateType ` - ` date ` or ` datetime ` objects passed in are wrapped in
251- these. Again, these classes also subclass ` date ` or ` datetime ` , and can be
252- used as such.
253- * ` FluentNone ` - in error conditions, such as a message referring to an argument
254- that hasn't been passed in, objects of this type are passed in.
255-
256- Custom functions should not throw errors, but return ` FluentNone ` instances to
257- indicate an error or missing data. Otherwise they should return unicode strings,
258- or instances of a ` FluentType ` subclass as above.
259-
260-
261- Known limitations and bugs
262- --------------------------
263-
264- * We do not yet support ` NUMBER(..., currencyDisplay="name") ` - see [ this python-babel
265- pull request] ( https://github.com/python-babel/babel/pull/585 ) which needs to
266- be merged and released.
267-
268- * Most options to ` DATETIME ` are not yet supported. See the [ MDN docs for
269- Intl.DateTimeFormat] ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat ) ,
270- the [ ECMA spec for
271- BasicFormatMatcher] ( http://www.ecma-international.org/ecma-402/1.0/#BasicFormatMatcher )
272- and the [ Intl.js
273- polyfill] ( https://github.com/andyearnshaw/Intl.js/blob/master/src/12.datetimeformat.js ) .
274-
275- Help with the above would be welcome!
276-
61+ For fluent.runtime, see the [ docs folder] ( fluent.runtime/docs ) or [ read them on
62+ readthedocs.org] ( https://fluent-runtime.readthedocs.io/en/latest/ ) .
27763
27864Discuss
27965-------
0 commit comments