@@ -44,7 +44,6 @@ python-fluent consists of two packages:
44
44
45
45
46
46
* ` fluent.runtime ` - methods for generating translations from FTL files.
47
- Documentation below.
48
47
49
48
To install:
50
49
@@ -59,221 +58,8 @@ PyPI also contains an old `fluent` package which is an older version of just
59
58
Usage
60
59
-----
61
60
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/ ) .
277
63
278
64
Discuss
279
65
-------
0 commit comments