format.py
Go to the documentation of this file.
1 # Copyright 2017 Mycroft AI Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 
16 from os.path import join
17 
18 from mycroft.util.lang import get_full_lang_code, get_primary_lang_code
19 
20 from mycroft.util.lang.format_en import *
21 from mycroft.util.lang.format_pt import *
22 from mycroft.util.lang.format_it import *
23 from mycroft.util.lang.format_sv import *
24 from mycroft.util.lang.format_hu import *
25 
26 from mycroft.util.lang.format_es import nice_number_es
27 from mycroft.util.lang.format_es import nice_time_es
28 from mycroft.util.lang.format_es import pronounce_number_es
29 from mycroft.util.lang.format_de import nice_number_de
30 from mycroft.util.lang.format_de import nice_time_de
31 from mycroft.util.lang.format_de import pronounce_number_de
32 from mycroft.util.lang.format_fr import nice_number_fr
33 from mycroft.util.lang.format_fr import nice_time_fr
34 from mycroft.util.lang.format_fr import pronounce_number_fr
35 from mycroft.util.lang.format_nl import nice_time_nl
36 from mycroft.util.lang.format_nl import pronounce_number_nl
37 from mycroft.util.lang.format_nl import nice_number_nl
38 from mycroft.util.lang.format_da import nice_number_da
39 from mycroft.util.lang.format_da import nice_time_da
40 from mycroft.util.lang.format_da import pronounce_number_da
41 
42 from collections import namedtuple
43 from padatious.util import expand_parentheses
44 import json
45 import os
46 import datetime
47 import re
48 
49 
50 def _translate_word(name, lang):
51  """ Helper to get word tranlations
52 
53  Args:
54  name (str): Word name. Returned as the default value if not translated.
55  lang (str): Language code, e.g. "en-us"
56 
57  Returns:
58  str: translated version of resource name
59  """
60  from mycroft.util import resolve_resource_file
61 
62  lang_code = get_full_lang_code(lang)
63 
64  filename = resolve_resource_file(join("text", lang_code, name+".word"))
65  if filename:
66  # open the file
67  try:
68  with open(filename, 'r', encoding='utf8') as f:
69  for line in f:
70  word = line.strip()
71  if word.startswith("#"):
72  continue # skip comment lines
73  return word
74  except Exception:
75  pass
76  return name # use resource name as the word
77 
78 
79 NUMBER_TUPLE = namedtuple(
80  'number',
81  ('x, xx, x0, x_in_x0, xxx, x00, x_in_x00, xx00, xx_in_xx00, x000, ' +
82  'x_in_x000, x0_in_x000, x_in_0x00'))
83 
84 
86  def __init__(self, config_path):
87  self.lang_config = {}
88  self.config_path = config_path
89 
90  def cache(self, lang):
91  if lang not in self.lang_config:
92  try:
93  # Attempt to load the language-specific formatting data
94  with open(self.config_path + '/' + lang + '/date_time.json',
95  'r') as lang_config_file:
96  self.lang_config[lang] = json.loads(
97  lang_config_file.read())
98  except FileNotFoundError:
99  # Fallback to English formatting
100  with open(self.config_path + '/en-us/date_time.json',
101  'r') as lang_config_file:
102  self.lang_config[lang] = json.loads(
103  lang_config_file.read())
104 
105  for x in ['decade_format', 'hundreds_format', 'thousand_format',
106  'year_format']:
107  i = 1
108  while self.lang_config[lang][x].get(str(i)):
109  self.lang_config[lang][x][str(i)]['re'] = (
110  re.compile(self.lang_config[lang][x][str(i)]['match']
111  ))
112  i = i + 1
113 
114  def _number_strings(self, number, lang):
115  x = (self.lang_config[lang]['number'].get(str(number % 10)) or
116  str(number % 10))
117  xx = (self.lang_config[lang]['number'].get(str(number % 100)) or
118  str(number % 100))
119  x_in_x0 = self.lang_config[lang]['number'].get(
120  str(int(number % 100 / 10))) or str(int(number % 100 / 10))
121  x0 = (self.lang_config[lang]['number'].get(
122  str(int(number % 100 / 10) * 10)) or
123  str(int(number % 100 / 10) * 10))
124  xxx = (self.lang_config[lang]['number'].get(str(number % 1000)) or
125  str(number % 1000))
126  x00 = (self.lang_config[lang]['number'].get(str(int(
127  number % 1000 / 100) * 100)) or
128  str(int(number % 1000 / 100) * 100))
129  x_in_x00 = self.lang_config[lang]['number'].get(str(int(
130  number % 1000 / 100))) or str(int(number % 1000 / 100))
131  xx00 = self.lang_config[lang]['number'].get(str(int(
132  number % 10000 / 100) * 100)) or str(int(number % 10000 / 100) *
133  100)
134  xx_in_xx00 = self.lang_config[lang]['number'].get(str(int(
135  number % 10000 / 100))) or str(int(number % 10000 / 100))
136  x000 = (self.lang_config[lang]['number'].get(str(int(
137  number % 10000 / 1000) * 1000)) or
138  str(int(number % 10000 / 1000) * 1000))
139  x_in_x000 = self.lang_config[lang]['number'].get(str(int(
140  number % 10000 / 1000))) or str(int(number % 10000 / 1000))
141  x0_in_x000 = self.lang_config[lang]['number'].get(str(int(
142  number % 10000 / 1000)*10)) or str(int(number % 10000 / 1000)*10)
143  x_in_0x00 = self.lang_config[lang]['number'].get(str(int(
144  number % 1000 / 100)) or str(int(number % 1000 / 100)))
145 
146  return NUMBER_TUPLE(
147  x, xx, x0, x_in_x0, xxx, x00, x_in_x00, xx00, xx_in_xx00, x000,
148  x_in_x000, x0_in_x000, x_in_0x00)
149 
150  def _format_string(self, number, format_section, lang):
151  s = self.lang_config[lang][format_section]['default']
152  i = 1
153  while self.lang_config[lang][format_section].get(str(i)):
154  e = self.lang_config[lang][format_section][str(i)]
155  if e['re'].match(str(number)):
156  return e['format']
157  i = i + 1
158  return s
159 
160  def _decade_format(self, number, number_tuple, lang):
161  s = self._format_string(number % 100, 'decade_format', lang)
162  return s.format(x=number_tuple.x, xx=number_tuple.xx,
163  x0=number_tuple.x0, x_in_x0=number_tuple.x_in_x0,
164  number=str(number % 100))
165 
166  def _number_format_hundreds(self, number, number_tuple, lang,
167  formatted_decade):
168  s = self._format_string(number % 1000, 'hundreds_format', lang)
169  return s.format(xxx=number_tuple.xxx, x00=number_tuple.x00,
170  x_in_x00=number_tuple.x_in_x00,
171  formatted_decade=formatted_decade,
172  number=str(number % 1000))
173 
174  def _number_format_thousand(self, number, number_tuple, lang,
175  formatted_decade, formatted_hundreds):
176  s = self._format_string(number % 10000, 'thousand_format', lang)
177  return s.format(x_in_x00=number_tuple.x_in_x00,
178  xx00=number_tuple.xx00,
179  xx_in_xx00=number_tuple.xx_in_xx00,
180  x000=number_tuple.x000,
181  x_in_x000=number_tuple.x_in_x000,
182  x0_in_x000=number_tuple.x0_in_x000,
183  x_in_0x00=number_tuple.x_in_0x00,
184  formatted_decade=formatted_decade,
185  formatted_hundreds=formatted_hundreds,
186  number=str(number % 10000))
187 
188  def date_format(self, dt, lang, now):
189  format_str = 'date_full'
190  if now:
191  if dt.year == now.year:
192  format_str = 'date_full_no_year'
193  if dt.month == now.month and dt.day > now.day:
194  format_str = 'date_full_no_year_month'
195 
196  tomorrow = now + datetime.timedelta(days=1)
197  yesterday = now - datetime.timedelta(days=1)
198  if tomorrow.date() == dt.date():
199  format_str = 'tomorrow'
200  elif now.date() == dt.date():
201  format_str = 'today'
202  elif yesterday.date() == dt.date():
203  format_str = 'yesterday'
204 
205  return self.lang_config[lang]['date_format'][format_str].format(
206  weekday=self.lang_config[lang]['weekday'][str(dt.weekday())],
207  month=self.lang_config[lang]['month'][str(dt.month)],
208  day=self.lang_config[lang]['date'][str(dt.day)],
209  formatted_year=self.year_format(dt, lang, False))
210 
211  def date_time_format(self, dt, lang, now, use_24hour, use_ampm):
212  date_str = self.date_format(dt, lang, now)
213  time_str = nice_time(dt, lang, use_24hour=use_24hour,
214  use_ampm=use_ampm)
215  return self.lang_config[lang]['date_time_format']['date_time'].format(
216  formatted_date=date_str, formatted_time=time_str)
217 
218  def year_format(self, dt, lang, bc):
219  number_tuple = self._number_strings(dt.year, lang)
220  formatted_bc = (
221  self.lang_config[lang]['year_format']['bc'] if bc else '')
222  formatted_decade = self._decade_format(
223  dt.year, number_tuple, lang)
224  formatted_hundreds = self._number_format_hundreds(
225  dt.year, number_tuple, lang, formatted_decade)
226  formatted_thousand = self._number_format_thousand(
227  dt.year, number_tuple, lang, formatted_decade, formatted_hundreds)
228 
229  s = self._format_string(dt.year, 'year_format', lang)
230 
231  return re.sub(' +', ' ',
232  s.format(
233  year=str(dt.year),
234  century=str(int(dt.year / 100)),
235  decade=str(dt.year % 100),
236  formatted_hundreds=formatted_hundreds,
237  formatted_decade=formatted_decade,
238  formatted_thousand=formatted_thousand,
239  bc=formatted_bc)).strip()
240 
241 
242 date_time_format = DateTimeFormat(
243  os.path.dirname(os.path.abspath(__file__)) + '/../res/text')
244 
245 
246 def nice_number(number, lang=None, speech=True, denominators=None):
247  """Format a float to human readable functions
248 
249  This function formats a float to human understandable functions. Like
250  4.5 becomes 4 and a half for speech and 4 1/2 for text
251  Args:
252  number (int or float): the float to format
253  lang (str): code for the language to use
254  speech (bool): format for speech (True) or display (False)
255  denominators (iter of ints): denominators to use, default [1 .. 20]
256  Returns:
257  (str): The formatted string.
258  """
259  # Convert to spoken representation in appropriate language
260  lang_code = get_primary_lang_code(lang)
261  if lang_code == "en":
262  return nice_number_en(number, speech, denominators)
263  elif lang_code == "es":
264  return nice_number_es(number, speech, denominators)
265  elif lang_code == "pt":
266  return nice_number_pt(number, speech, denominators)
267  elif lang_code == "it":
268  return nice_number_it(number, speech, denominators)
269  elif lang_code == "fr":
270  return nice_number_fr(number, speech, denominators)
271  elif lang_code == "sv":
272  return nice_number_sv(number, speech, denominators)
273  elif lang_code == "de":
274  return nice_number_de(number, speech, denominators)
275  elif lang_code == "hu":
276  return nice_number_hu(number, speech, denominators)
277  elif lang_code == "nl":
278  return nice_number_nl(number, speech, denominators)
279  elif lang_code == "da":
280  return nice_number_da(number, speech, denominators)
281 
282  # Default to the raw number for unsupported languages,
283  # hopefully the STT engine will pronounce understandably.
284  return str(number)
285 
286 
287 def nice_time(dt, lang=None, speech=True, use_24hour=False,
288  use_ampm=False):
289  """
290  Format a time to a comfortable human format
291 
292  For example, generate 'five thirty' for speech or '5:30' for
293  text display.
294 
295  Args:
296  dt (datetime): date to format (assumes already in local timezone)
297  lang (str): code for the language to use
298  speech (bool): format for speech (default/True) or display (False)
299  use_24hour (bool): output in 24-hour/military or 12-hour format
300  use_ampm (bool): include the am/pm for 12-hour format
301  Returns:
302  (str): The formatted time string
303  """
304  lang_code = get_primary_lang_code(lang)
305  if lang_code == "en":
306  return nice_time_en(dt, speech, use_24hour, use_ampm)
307  elif lang_code == "es":
308  return nice_time_es(dt, speech, use_24hour, use_ampm)
309  elif lang_code == "it":
310  return nice_time_it(dt, speech, use_24hour, use_ampm)
311  elif lang_code == "fr":
312  return nice_time_fr(dt, speech, use_24hour, use_ampm)
313  elif lang_code == "de":
314  return nice_time_de(dt, speech, use_24hour, use_ampm)
315  elif lang_code == "hu":
316  return nice_time_hu(dt, speech, use_24hour, use_ampm)
317  elif lang_code == "nl":
318  return nice_time_nl(dt, speech, use_24hour, use_ampm)
319  elif lang_code == "da":
320  return nice_time_da(dt, speech, use_24hour, use_ampm)
321  elif lang_code == "pt":
322  return nice_time_pt(dt, speech, use_24hour, use_ampm)
323 
324  # TODO: Other languages
325  return str(dt)
326 
327 
328 def pronounce_number(number, lang=None, places=2, short_scale=True,
329  scientific=False):
330  """
331  Convert a number to it's spoken equivalent
332 
333  For example, '5' would be 'five'
334 
335  Args:
336  number: the number to pronounce
337  short_scale (bool) : use short (True) or long scale (False)
338  https://en.wikipedia.org/wiki/Names_of_large_numbers
339  scientific (bool) : convert and pronounce in scientific notation
340  Returns:
341  (str): The pronounced number
342  """
343  lang_code = get_primary_lang_code(lang)
344  if lang_code == "en":
345  return pronounce_number_en(number, places=places,
346  short_scale=short_scale,
347  scientific=scientific)
348  elif lang_code == "it":
349  return pronounce_number_it(number, places=places,
350  short_scale=short_scale,
351  scientific=scientific)
352  elif lang_code == "es":
353  return pronounce_number_es(number, places=places)
354  elif lang_code == "fr":
355  return pronounce_number_fr(number, places=places)
356  elif lang_code == "de":
357  return pronounce_number_de(number, places=places)
358  elif lang_code == "hu":
359  return pronounce_number_hu(number, places=places)
360  elif lang_code == "nl":
361  return pronounce_number_nl(number, places=places)
362  elif lang_code == "da":
363  return pronounce_number_da(number, places=places)
364  elif lang_code == "pt":
365  return pronounce_number_pt(number, places=places)
366 
367  # Default to just returning the numeric value
368  return str(number)
369 
370 
371 def nice_date(dt, lang=None, now=None):
372  """
373  Format a datetime to a pronounceable date
374 
375  For example, generates 'tuesday, june the fifth, 2018'
376  Args:
377  dt (datetime): date to format (assumes already in local timezone)
378  lang (string): the language to use, use Mycroft default language if not
379  provided
380  now (datetime): Current date. If provided, the returned date for speech
381  will be shortened accordingly: No year is returned if now is in the
382  same year as td, no month is returned if now is in the same month
383  as td. If now and td is the same day, 'today' is returned.
384  Returns:
385  (str): The formatted date string
386  """
387  full_code = get_full_lang_code(lang)
388  date_time_format.cache(full_code)
389 
390  return date_time_format.date_format(dt, full_code, now)
391 
392 
393 def nice_date_time(dt, lang=None, now=None, use_24hour=False,
394  use_ampm=False):
395  """
396  Format a datetime to a pronounceable date and time
397 
398  For example, generate 'tuesday, june the fifth, 2018 at five thirty'
399 
400  Args:
401  dt (datetime): date to format (assumes already in local timezone)
402  lang (string): the language to use, use Mycroft default language if
403  not provided
404  now (datetime): Current date. If provided, the returned date for
405  speech will be shortened accordingly: No year is returned if
406  now is in the same year as td, no month is returned if now is
407  in the same month as td. If now and td is the same day, 'today'
408  is returned.
409  use_24hour (bool): output in 24-hour/military or 12-hour format
410  use_ampm (bool): include the am/pm for 12-hour format
411  Returns:
412  (str): The formatted date time string
413  """
414 
415  full_code = get_full_lang_code(lang)
416  date_time_format.cache(full_code)
417 
418  return date_time_format.date_time_format(dt, full_code, now, use_24hour,
419  use_ampm)
420 
421 
422 def nice_year(dt, lang=None, bc=False):
423  """
424  Format a datetime to a pronounceable year
425 
426  For example, generate 'nineteen-hundred and eighty-four' for year 1984
427 
428  Args:
429  dt (datetime): date to format (assumes already in local timezone)
430  lang (string): the language to use, use Mycroft default language if
431  not provided
432  bc (bool) pust B.C. after the year (python does not support dates
433  B.C. in datetime)
434  Returns:
435  (str): The formatted year string
436  """
437 
438  full_code = get_full_lang_code(lang)
439  date_time_format.cache(full_code)
440 
441  return date_time_format.year_format(dt, full_code, bc)
442 
443 
444 def nice_duration(duration, lang=None, speech=True):
445  """ Convert duration in seconds to a nice spoken timespan
446 
447  Examples:
448  duration = 60 -> "1:00" or "one minute"
449  duration = 163 -> "2:43" or "two minutes forty three seconds"
450 
451  Args:
452  duration: time, in seconds
453  lang (str, optional): a BCP-47 language code, None for default
454  speech (bool): format for speech (True) or display (False)
455  Returns:
456  str: timespan as a string
457  """
458  if type(duration) is datetime.timedelta:
459  duration = duration.total_seconds()
460 
461  # Do traditional rounding: 2.5->3, 3.5->4, plus this
462  # helps in a few cases of where calculations generate
463  # times like 2:59:59.9 instead of 3:00.
464  duration += 0.5
465 
466  days = int(duration // 86400)
467  hours = int(duration // 3600 % 24)
468  minutes = int(duration // 60 % 60)
469  seconds = int(duration % 60)
470 
471  if speech:
472  out = ""
473  if days > 0:
474  out += pronounce_number(days, lang) + " "
475  if days == 1:
476  out += _translate_word("day", lang)
477  else:
478  out += _translate_word("days", lang)
479  out += " "
480  if hours > 0:
481  if out:
482  out += " "
483  out += pronounce_number(hours, lang) + " "
484  if hours == 1:
485  out += _translate_word("hour", lang)
486  else:
487  out += _translate_word("hours", lang)
488  if minutes > 0:
489  if out:
490  out += " "
491  out += pronounce_number(minutes, lang) + " "
492  if minutes == 1:
493  out += _translate_word("minute", lang)
494  else:
495  out += _translate_word("minutes", lang)
496  if seconds > 0:
497  if out:
498  out += " "
499  out += pronounce_number(seconds, lang) + " "
500  if seconds == 1:
501  out += _translate_word("second", lang)
502  else:
503  out += _translate_word("seconds", lang)
504  else:
505  # M:SS, MM:SS, H:MM:SS, Dd H:MM:SS format
506  out = ""
507  if days > 0:
508  out = str(days) + "d "
509  if hours > 0 or days > 0:
510  out += str(hours) + ":"
511  if minutes < 10 and (hours > 0 or days > 0):
512  out += "0"
513  out += str(minutes)+":"
514  if seconds < 10:
515  out += "0"
516  out += str(seconds)
517 
518  return out
519 
520 
521 def join_list(items, connector, sep=None, lang=None):
522  """ Join a list into a phrase using the given connector word
523 
524  Examples:
525  join_list([1,2,3], "and") -> "1, 2 and 3"
526  join_list([1,2,3], "and", ";") -> "1; 2 and 3"
527 
528  Args:
529  items(array): items to be joined
530  connector(str): connecting word (resource name), like "and" or "or"
531  sep(str, optional): separator character, default = ","
532  Returns:
533  str: the connected list phrase
534  """
535 
536  if not items:
537  return ""
538  if len(items) == 1:
539  return str(items[0])
540 
541  if not sep:
542  sep = ", "
543  else:
544  sep += " "
545  return (sep.join(str(item) for item in items[:-1]) +
546  " " + _translate_word(connector, lang) +
547  " " + items[-1])
548 
549 
550 def expand_options(parentheses_line: str) -> list:
551  """
552  Convert 'test (a|b)' -> ['test a', 'test b']
553  Args:
554  parentheses_line: Input line to expand
555  Returns:
556  List of expanded possibilities
557  """
558  # 'a(this|that)b' -> [['a', 'this', 'b'], ['a', 'that', 'b']]
559  options = expand_parentheses(re.split(r'([(|)])', parentheses_line))
560  return [re.sub(r'\s+', ' ', ' '.join(i)).strip() for i in options]
def nice_date(dt, lang=None, now=None)
Definition: format.py:371
def nice_number_nl(number, speech, denominators)
Definition: format_nl.py:100
def nice_time_en(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_en.py:229
def resolve_resource_file(res_name)
def nice_time_it(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_it.py:397
def nice_time_fr(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_fr.py:205
def nice_number_da(number, speech, denominators)
Definition: format_da.py:101
def year_format(self, dt, lang, bc)
Definition: format.py:218
def pronounce_number_fr(num, places=2)
Definition: format_fr.py:143
def nice_time_hu(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_hu.py:291
def nice_duration(duration, lang=None, speech=True)
Definition: format.py:444
def nice_time_de(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_de.py:267
def nice_number_en(number, speech, denominators)
Definition: format_en.py:24
def _number_format_thousand(self, number, number_tuple, lang, formatted_decade, formatted_hundreds)
Definition: format.py:175
def pronounce_number_es(num, places=2)
Definition: format_es.py:146
def nice_time(dt, lang=None, speech=True, use_24hour=False, use_ampm=False)
Definition: format.py:288
def _format_string(self, number, format_section, lang)
Definition: format.py:150
def pronounce_number_de(num, places=2)
Definition: format_de.py:138
def __init__(self, config_path)
Definition: format.py:86
def nice_time_nl(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_nl.py:264
def _translate_word(name, lang)
Definition: format.py:50
def date_time_format(self, dt, lang, now, use_24hour, use_ampm)
Definition: format.py:211
def pronounce_number_it(num, places=2, short_scale=False, scientific=False)
Definition: format_it.py:238
def nice_number_es(number, speech, denominators)
Definition: format_es.py:77
def pronounce_number_en(num, places=2, short_scale=True, scientific=False)
Definition: format_en.py:69
def pronounce_number(number, lang=None, places=2, short_scale=True, scientific=False)
Definition: format.py:329
def nice_number_de(number, speech, denominators)
Definition: format_de.py:100
def nice_number_it(number, speech, denominators)
Definition: format_it.py:181
def _number_strings(self, number, lang)
Definition: format.py:114
def pronounce_number_da(num, places=2)
Definition: format_da.py:140
def nice_number_hu(number, speech, denominators)
Definition: format_hu.py:109
def nice_date_time(dt, lang=None, now=None, use_24hour=False, use_ampm=False)
Definition: format.py:394
def nice_year(dt, lang=None, bc=False)
Definition: format.py:422
def nice_time_es(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_es.py:207
def nice_time_da(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_da.py:275
def pronounce_number_pt(num, places=2)
Definition: format_pt.py:77
def join_list(items, connector, sep=None, lang=None)
Definition: format.py:521
def nice_number(number, lang=None, speech=True, denominators=None)
Definition: format.py:246
def date_format(self, dt, lang, now)
Definition: format.py:188
def nice_number_pt(number, speech, denominators)
Definition: format_pt.py:23
def pronounce_number_hu(num, places=2)
Definition: format_hu.py:154
def pronounce_number_nl(num, places=2)
Definition: format_nl.py:138
def _decade_format(self, number, number_tuple, lang)
Definition: format.py:160
def nice_time_pt(dt, speech=True, use_24hour=False, use_ampm=False)
Definition: format_pt.py:118
def nice_number_sv(number, speech, denominators)
Definition: format_sv.py:43
def nice_number_fr(number, speech, denominators)
Definition: format_fr.py:74
def get(phrase, lang=None, context=None)
def _number_format_hundreds(self, number, number_tuple, lang, formatted_decade)
Definition: format.py:167


mycroft_ros
Author(s):
autogenerated on Mon Apr 26 2021 02:35:40