# OpenVoiceOS Lingua Franca
OpenVoiceOS's multilingual text parsing and formatting library
Lingua Franca (_noun_)<br>
> a framework that is adopted as the common language between speakers with different native tongues</dr>
This project has been forked from mycroft-core, it replaces it!
:warning: `pip install ovos-lingua-franca` will also `pip uninstall lingua-franca -y` :warning:
- [Lingua Franca](#lingua-franca)
- [Formatting](#formatting)
- [Pronounce numbers](#pronounce-numbers)
- [Pronounce datetime objects](#pronounce-datetime-objects)
- [Pronounce durations](#pronounce-durations)
- [Parsing](#parsing)
- [Extract numbers](#extract-numbers)
- [Extract durations](#extract-durations)
- [Extract dates](#extract-dates)
- [Contributing to this project](#contributing-to-this-project)
- [0. Sign a Contributor Licensing Agreement](#0-sign-a-contributor-licensing-agreement)
- [1. Setup a local copy of the project](#1-setup-a-local-copy-of-the-project)
- [2. Writing tests](#2-writing-tests)
- [3. Run tests to confirm they fail](#3-run-tests-to-confirm-they-fail)
- [4. Write code](#4-write-code)
- [5. Document your code](#5-document-your-code)
- [6. Try it in Mycroft](#6-try-it-in-mycroft)
- [7. Commit changes](#7-commit-changes)
- [8. Submit a PR](#8-submit-a-pr)
- [9. Waiting for a review](#9-waiting-for-a-review)
- [Credits](#credits)
## Formatting
Convert data into spoken equivalents
### Pronounce numbers
spoken versions of numbers
```python
from lingua_franca.format import nice_number, pronounce_number
assert nice_number(25/6) == "4 and a sixth"
assert nice_number(201) == "201"
assert nice_number(3.14159269) == "3 and a seventh"
assert pronounce_number(3.14159269) == "three point one four"
assert pronounce_number(0) == "zero"
assert pronounce_number(10) == "ten"
assert pronounce_number(201) == "two hundred and one"
assert pronounce_number(102.3) == "one hundred and two point three"
assert pronounce_number(
4092949192) == "four billion, ninety two million, nine hundred and forty nine thousand, one hundred and ninety two"
assert pronounce_number(100034000000299792458, short_scale=True) == \
"one hundred quintillion, thirty four quadrillion, " \
"two hundred and ninety nine million, seven hundred and ninety " \
"two thousand, four hundred and fifty eight"
assert pronounce_number(100034000000299792458, short_scale=False) == \
"one hundred trillion, thirty four thousand billion, " \
"two hundred and ninety nine million, seven hundred and ninety " \
"two thousand, four hundred and fifty eight"
```
### Pronounce datetime objects
spoken date for datetime.datetime objects
```python
from lingua_franca.format import nice_date, nice_date_time, nice_time
import datetime
dt = datetime.datetime(2017, 1, 31, 13, 22, 3)
assert nice_date(dt) == "tuesday, january thirty-first, twenty seventeen"
assert nice_time(dt) == "one twenty two"
assert nice_time(dt, use_ampm=True) == "one twenty two p.m."
assert nice_time(dt, speech=False) == "1:22"
assert nice_time(dt, speech=False, use_ampm=True) == "1:22 PM"
assert nice_time(dt, speech=False, use_24hour=True) == "13:22"
assert nice_time(dt, speech=False, use_24hour=True, use_ampm=True) == "13:22"
assert nice_time(dt, use_24hour=True, use_ampm=True) == "thirteen twenty two"
assert nice_time(dt, use_24hour=True, use_ampm=False) == "thirteen twenty two"
assert nice_date_time(dt) == "tuesday, january thirty-first, twenty seventeen at one twenty two"
```
### Pronounce durations
spoken number of seconds or datetime.timedelta objects
```python
from lingua_franca.format import nice_duration
assert nice_duration(1) == "one second"
assert nice_duration(3) == "three seconds"
assert nice_duration(1, speech=False) == "0:01"
assert nice_duration(61), "one minute one second"
assert nice_duration(61, speech=False) == "1:01"
assert nice_duration(5000) == "one hour twenty three minutes twenty seconds"
assert nice_duration(5000, speech=False), "1:23:20"
assert nice_duration(50000) == "thirteen hours fifty three minutes twenty seconds"
assert nice_duration(50000, speech=False) == "13:53:20"
assert nice_duration(500000) == "five days eighteen hours fifty three minutes twenty seconds"
assert nice_duration(500000, speech=False), "5d 18:53:20"
from datetime import timedelta
assert nice_duration(timedelta(seconds=500000), speech=False) == "5d 18:53:20"
```
## Parsing
Extract data from natural language text
### Extract numbers
```python
from lingua_franca.parse import extract_number, extract_numbers
# extract a number
assert extract_number("nothing") is False
assert extract_number("two million five hundred thousand tons of spinning "
"metal") == 2500000
assert extract_number("six trillion") == 6000000000000.0
assert extract_number("six trillion", short_scale=False) == 6e+18
assert extract_number("1 and 3/4 cups") == 1.75
assert extract_number("1 cup and a half") == 1.5
## extracts all numbers
assert extract_numbers("nothing") == []
assert extract_numbers("this is a one twenty one test") == [1.0, 21.0]
assert extract_numbers("1 dog, seven pigs, macdonald had a farm, "
"3 times 5 macarena") == [1, 7, 3, 5]
```
### Extract durations
extract datetime.timedelta objects
```python
## extract durations
from lingua_franca.parse import extract_duration
from datetime import timedelta
assert extract_duration("nothing") == (None, 'nothing')
assert extract_duration("Nineteen minutes past the hour") == (
timedelta(minutes=19),
"past the hour")
assert extract_duration("wake me up in three weeks, four hundred ninety seven"
" days, and three hundred 91.6 seconds") == (
timedelta(weeks=3, days=497, seconds=391.6),
"wake me up in , , and")
assert extract_duration(
"The movie is one hour, fifty seven and a half minutes long") == (
timedelta(hours=1, minutes=57.5),
"the movie is , long")
```
### Extract dates
extract datetime.datetime objects
```python
## extract date times
from datetime import datetime
from lingua_franca.parse import extract_datetime, normalize
def extractWithFormat(text):
date = datetime(2017, 6, 27, 13, 4) # Tue June 27, 2017 @ 1:04pm
[extractedDate, leftover] = extract_datetime(text, date)
extractedDate = extractedDate.strftime("%Y-%m-%d %H:%M:%S")
return [extractedDate, leftover]
def testExtract(text, expected_date, expected_leftover):
res = extractWithFormat(normalize(text))
assert res[0] == expected_date
assert res[1] == expected_leftover
testExtract("now is the time",
"2017-06-27 13:04:00", "is time")
testExtract("in a couple minutes",
"2017-06-27 13:06:00", "")
testExtract("What is the day after tomorrow's weather?",
"2017-06-29 00:00:00", "what is weather")
testExtract("Remind me at 10:45 pm",
"2017-06-27 22:45:00", "remind me")
testExtract("what is the weather on friday morning",
"2017-06-30 08:00:00", "what is weather")
testExtract("what is tomorrow's weather",
"2017-06-28 00:00:00", "what is weather")
testExtract("remind me to call mom next tuesday",
"2017-07-04 00:00:00", "remind me to call mom")
testExtract("remind me to call mom in 3 weeks",
"2017-07-18 00:00:00", "remind me to call mom")
testExtract("set an alarm for tonight 9:30",
"2017-06-27 21:30:00", "set alarm")
testExtract("on the evening of june 5th 2017 remind me to call my mother",
"2017-06-05 19:00:00", "remind me to call my mother")
```
## Getting Started
### Loading a language
Before using Lingua Franca's other functions, you'll need to load one or more languages into memory, using part or all of a
BCP-47 language code:
```python
# Load a language
lingua_franca.load_language('en')
# Load multiple languages at once
#
# If no default language is set, the first
# element will become the default
lingua_franca.load_languages(['en', 'es'])
# Change the default language
lingua_franca.set_default_language('es')
```
See the documentation for more information about loading and unloading languages.
### Calling localized functions
Most of Lingua Franca's functions have been localized. You can call a function in any language you've loaded; this is always specified by the function's `lang` parameter. If you omit that parameter, the function will be called in the current default language.
Example:
```python
>>> from lingua_franca import load_languages, \
set_default_lang, parse
>>> load_languages(['es', 'en'])
>>> parse.extract_number("uno")
1
>>> parse.extract_number("one")
False
>>> parse.extract_number("one", lang='en')
1
>>> set_default_lang('en')
>>> parse.extract_number("uno")
False
>>> parse.extract_number("one")
1
```
In some languages, certain parameters have no effect, either because
those parameters do not apply, or because the localization is not complete.
It's important to remember that Lingua Franca is in alpha. Support for a
particular language may be inconsistent, and one language's version of a
complex function might be outdated compared with another.
New functionality usually starts in the languages spoken by major
contributors. If your language's functions are lacking, we'd love your help
improving them! (See below, "Contributing.")
## Contributing to this project
We welcome all contributions to Lingua Franca. To get started:
### 0. Sign a Contributor Licensing Agreement
To protect yourself, the project, and users of Mycroft technologies, we require a Contributor Licensing Agreement (CLA) before accepting any code contribution. This agreement makes it crystal clear that, along with your code, you are offering a license to use it within the confines of this project. You retain ownership of the code, this is just a license.
You will also be added to [our list of excellent human beings](https://github.com/MycroftAI/contributors)!
Please visit https://mycroft.ai/cla to initiate this one-time signing.
### 1. Setup a local copy of the project
1. [Fork the project](https://help.github.com/articles/fork-a-repo/) to create your own copy.
2. Clone the repository and change into that directory
```bash
git clone https://github.com/your-username/lingua-franca/
cd lingua-franca
```
3. Setup a lightweight virtual environment (venv) for the project. This creates an isolated environment that can have it's own independent set of installed Python packages.
```bash
python3 -m venv .venv
source .venv/bin/activate
```
To exit the venv you can run `deactivate` or close the terminal window.
4. Install the package and it's dependencies
```bash
pip install wheel
python -m pip install .
pip install pytest
python setup.py install
```
5. To check that everything is installed correctly, let's run the existing test-suite.
```bash
pytest
```
### 2. Have a look at the project's structure
The package's layout is described in `project-structure.md`, along with some important notes. It's pretty
intuitive, but uniform file and function names are important to Lingua Franca's operation.
### 3. Writing tests
We utilize a Test Driven Development (TDD) methodology so the first step is always to add tests for whatever you want to add or fix. If it's a bug, we must not have a test that covers that specific case, so we want to add another test. If you are starting on a new language then you can take a look at the tests for other languages to get started.
Tests are all located in `lingua_franca/test`.
Each language should have two test files:
- `test_format_lang.py`
- `test_parse_lang.py`
### 4. Run tests to confirm they fail
Generally, using TDD, all tests should fail when they are first added. If the test is passing when you haven't yet fixed the bug or added the functionality, something must be wrong with the test or the test runner.
```bash
pytest
```
### 5. Write code
Now we can add our new code. There are three main files for each language:
- `common_data_lang.py`
Common data that can be used across formatting and parsing such as dictionaries of number names.
- `format_lang.py`
All formatting functions for this language.
- `parse_lang.py`
All parsing functions for this language.
Since we have already written our unit tests, we can run these regularly to see our progress.
### 6. Document your code
Document code using [Google-style docstrings](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html). Our automated documentation tools expect that format. All functions and class methods that are expected to be called externally should include a docstring. (And those that aren't should be [prefixed with a single underscore](https://docs.python.org/3/tutorial/classes.html#private-variables).
### 7. Try it in Mycroft
Lingua Franca is installed by default when you install Mycroft-core, but for development you generally have this repo cloned elsewhere on your computer. You can use your changes in Mycroft by installing it in the Mycroft virtual environment.
If you added the Mycroft helper commands during setup you can just use:
```bash
mycroft-pip install /path/to/your/lingua-franca
```
Otherwise you need to activate that venv manually:
```bash
cd ~/mycroft-core
source venv-activate.sh
pip install /path/to/your/lingua-franca
```
Now, when talking with Mycroft, it will be using your development version of Lingua Franca.
### 8. Commit changes
Make commits in logical units, and describe them thoroughly. If addressing documented issue, use the issue identifier at the very beginning of each commit. For instance:
```bash
git commit -m "Issues-123 - Fix 'demain' date extraction in French"
```
### 9. Submit a PR
Once your changes are ready for review, [create a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request).
Like commit messages, the PR title and description should properly describe the changes you have made, along with any additional information that reviewers who do not speak your language might need to understand.
### 10. Waiting for a review
While you wait for a review of your contribution, why not take a moment to review some other pull requests? This is a great way to learn and help progress the queue of pull requests, which means your contribution will be seen more quickly!
## Credits
Though it is now a standalone package, Lingua Franca's codebase was a spinoff from Mycroft-core. In addition to those represented in Lingua Franca's git log, a great many people contributed to this code before the spinoff.
Although all are listed in MycroftAI's [List of Excellent People](https://github.com/MycroftAI/contributors), it seems proper to acknowledge the specific individuals who helped write *this* package, since they are no longer represented in `git log`.
To the best of the maintainers' knowledge, all of the "lost" contributors are listed in `pre-spinoff-credits.md`. Names are listed as they appeared in `git log`, or as they are known to the Mycroft community.
Those who've contributed since the spinoff are, of course, in Lingua Franca's `git log` and the GitHub "Contributors" pane. All contributors are on the List of Excellent People, regardless of when they contributed.
If you contributed to the original code, and your name is missing from `pre-spinoff-credits.md`, please inform a maintainer or file an issue, so we can give credit where credit is due!
Raw data
{
"_id": null,
"home_page": "https://github.com/OpenVoiceOS/ovos-lingua-franca",
"name": "ovos-lingua-franca",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "",
"author": "Mycroft AI / OVOS",
"author_email": "jarbasai@mailfence.com",
"download_url": "",
"platform": null,
"description": "# OpenVoiceOS Lingua Franca\n\nOpenVoiceOS's multilingual text parsing and formatting library\n\nLingua Franca (_noun_)<br>\n> a framework that is adopted as the common language between speakers with different native tongues</dr>\n\nThis project has been forked from mycroft-core, it replaces it!\n\n:warning: `pip install ovos-lingua-franca` will also `pip uninstall lingua-franca -y` :warning:\n\n- [Lingua Franca](#lingua-franca)\n - [Formatting](#formatting)\n - [Pronounce numbers](#pronounce-numbers)\n - [Pronounce datetime objects](#pronounce-datetime-objects)\n - [Pronounce durations](#pronounce-durations)\n - [Parsing](#parsing)\n - [Extract numbers](#extract-numbers)\n - [Extract durations](#extract-durations)\n - [Extract dates](#extract-dates)\n - [Contributing to this project](#contributing-to-this-project)\n - [0. Sign a Contributor Licensing Agreement](#0-sign-a-contributor-licensing-agreement)\n - [1. Setup a local copy of the project](#1-setup-a-local-copy-of-the-project)\n - [2. Writing tests](#2-writing-tests)\n - [3. Run tests to confirm they fail](#3-run-tests-to-confirm-they-fail)\n - [4. Write code](#4-write-code)\n - [5. Document your code](#5-document-your-code)\n - [6. Try it in Mycroft](#6-try-it-in-mycroft)\n - [7. Commit changes](#7-commit-changes)\n - [8. Submit a PR](#8-submit-a-pr)\n - [9. Waiting for a review](#9-waiting-for-a-review)\n - [Credits](#credits)\n\n## Formatting\n\nConvert data into spoken equivalents\n\n### Pronounce numbers\n\nspoken versions of numbers\n\n```python\nfrom lingua_franca.format import nice_number, pronounce_number\n\nassert nice_number(25/6) == \"4 and a sixth\"\nassert nice_number(201) == \"201\"\nassert nice_number(3.14159269) == \"3 and a seventh\"\n\nassert pronounce_number(3.14159269) == \"three point one four\"\nassert pronounce_number(0) == \"zero\"\nassert pronounce_number(10) == \"ten\"\nassert pronounce_number(201) == \"two hundred and one\"\nassert pronounce_number(102.3) == \"one hundred and two point three\"\nassert pronounce_number(\n 4092949192) == \"four billion, ninety two million, nine hundred and forty nine thousand, one hundred and ninety two\"\n\nassert pronounce_number(100034000000299792458, short_scale=True) == \\\n \"one hundred quintillion, thirty four quadrillion, \" \\\n \"two hundred and ninety nine million, seven hundred and ninety \" \\\n \"two thousand, four hundred and fifty eight\"\n\nassert pronounce_number(100034000000299792458, short_scale=False) == \\\n \"one hundred trillion, thirty four thousand billion, \" \\\n \"two hundred and ninety nine million, seven hundred and ninety \" \\\n \"two thousand, four hundred and fifty eight\"\n```\n\n### Pronounce datetime objects\n\nspoken date for datetime.datetime objects\n\n```python\nfrom lingua_franca.format import nice_date, nice_date_time, nice_time\nimport datetime\n\ndt = datetime.datetime(2017, 1, 31, 13, 22, 3)\n\nassert nice_date(dt) == \"tuesday, january thirty-first, twenty seventeen\"\n\nassert nice_time(dt) == \"one twenty two\"\nassert nice_time(dt, use_ampm=True) == \"one twenty two p.m.\"\nassert nice_time(dt, speech=False) == \"1:22\"\nassert nice_time(dt, speech=False, use_ampm=True) == \"1:22 PM\"\nassert nice_time(dt, speech=False, use_24hour=True) == \"13:22\"\nassert nice_time(dt, speech=False, use_24hour=True, use_ampm=True) == \"13:22\"\nassert nice_time(dt, use_24hour=True, use_ampm=True) == \"thirteen twenty two\"\nassert nice_time(dt, use_24hour=True, use_ampm=False) == \"thirteen twenty two\"\n\nassert nice_date_time(dt) == \"tuesday, january thirty-first, twenty seventeen at one twenty two\"\n```\n\n### Pronounce durations\n\nspoken number of seconds or datetime.timedelta objects\n\n```python\nfrom lingua_franca.format import nice_duration\n\n\nassert nice_duration(1) == \"one second\"\nassert nice_duration(3) == \"three seconds\"\nassert nice_duration(1, speech=False) == \"0:01\"\nassert nice_duration(61), \"one minute one second\"\nassert nice_duration(61, speech=False) == \"1:01\"\nassert nice_duration(5000) == \"one hour twenty three minutes twenty seconds\"\nassert nice_duration(5000, speech=False), \"1:23:20\"\nassert nice_duration(50000) == \"thirteen hours fifty three minutes twenty seconds\"\nassert nice_duration(50000, speech=False) == \"13:53:20\"\nassert nice_duration(500000) == \"five days eighteen hours fifty three minutes twenty seconds\"\nassert nice_duration(500000, speech=False), \"5d 18:53:20\"\n\nfrom datetime import timedelta\n\nassert nice_duration(timedelta(seconds=500000), speech=False) == \"5d 18:53:20\"\n```\n\n## Parsing\n\nExtract data from natural language text\n\n### Extract numbers\n\n```python\nfrom lingua_franca.parse import extract_number, extract_numbers\n\n# extract a number\nassert extract_number(\"nothing\") is False\nassert extract_number(\"two million five hundred thousand tons of spinning \"\n \"metal\") == 2500000\nassert extract_number(\"six trillion\") == 6000000000000.0\nassert extract_number(\"six trillion\", short_scale=False) == 6e+18\n\nassert extract_number(\"1 and 3/4 cups\") == 1.75\nassert extract_number(\"1 cup and a half\") == 1.5\n\n## extracts all numbers\nassert extract_numbers(\"nothing\") == []\nassert extract_numbers(\"this is a one twenty one test\") == [1.0, 21.0]\nassert extract_numbers(\"1 dog, seven pigs, macdonald had a farm, \"\n \"3 times 5 macarena\") == [1, 7, 3, 5]\n```\n\n### Extract durations\n\nextract datetime.timedelta objects\n\n```python\n## extract durations\nfrom lingua_franca.parse import extract_duration\nfrom datetime import timedelta\n\nassert extract_duration(\"nothing\") == (None, 'nothing')\n\nassert extract_duration(\"Nineteen minutes past the hour\") == (\n timedelta(minutes=19),\n \"past the hour\")\nassert extract_duration(\"wake me up in three weeks, four hundred ninety seven\"\n \" days, and three hundred 91.6 seconds\") == (\n timedelta(weeks=3, days=497, seconds=391.6),\n \"wake me up in , , and\")\nassert extract_duration(\n \"The movie is one hour, fifty seven and a half minutes long\") == (\n timedelta(hours=1, minutes=57.5),\n \"the movie is , long\")\n```\n\n### Extract dates\n\nextract datetime.datetime objects\n\n```python\n## extract date times\nfrom datetime import datetime\nfrom lingua_franca.parse import extract_datetime, normalize\n\ndef extractWithFormat(text):\n date = datetime(2017, 6, 27, 13, 4) # Tue June 27, 2017 @ 1:04pm\n [extractedDate, leftover] = extract_datetime(text, date)\n extractedDate = extractedDate.strftime(\"%Y-%m-%d %H:%M:%S\")\n return [extractedDate, leftover]\n\n\ndef testExtract(text, expected_date, expected_leftover):\n res = extractWithFormat(normalize(text))\n assert res[0] == expected_date\n assert res[1] == expected_leftover\n\n\ntestExtract(\"now is the time\",\n \"2017-06-27 13:04:00\", \"is time\")\ntestExtract(\"in a couple minutes\",\n \"2017-06-27 13:06:00\", \"\")\ntestExtract(\"What is the day after tomorrow's weather?\",\n \"2017-06-29 00:00:00\", \"what is weather\")\ntestExtract(\"Remind me at 10:45 pm\",\n \"2017-06-27 22:45:00\", \"remind me\")\ntestExtract(\"what is the weather on friday morning\",\n \"2017-06-30 08:00:00\", \"what is weather\")\ntestExtract(\"what is tomorrow's weather\",\n \"2017-06-28 00:00:00\", \"what is weather\")\ntestExtract(\"remind me to call mom next tuesday\",\n \"2017-07-04 00:00:00\", \"remind me to call mom\")\ntestExtract(\"remind me to call mom in 3 weeks\",\n \"2017-07-18 00:00:00\", \"remind me to call mom\")\ntestExtract(\"set an alarm for tonight 9:30\",\n \"2017-06-27 21:30:00\", \"set alarm\")\ntestExtract(\"on the evening of june 5th 2017 remind me to call my mother\",\n \"2017-06-05 19:00:00\", \"remind me to call my mother\")\n\n```\n\n## Getting Started\n\n### Loading a language\n\nBefore using Lingua Franca's other functions, you'll need to load one or more languages into memory, using part or all of a\nBCP-47 language code:\n\n```python\n# Load a language\nlingua_franca.load_language('en')\n\n# Load multiple languages at once\n#\n# If no default language is set, the first\n# element will become the default\nlingua_franca.load_languages(['en', 'es'])\n\n# Change the default language\nlingua_franca.set_default_language('es')\n```\n\nSee the documentation for more information about loading and unloading languages.\n\n### Calling localized functions\n\nMost of Lingua Franca's functions have been localized. You can call a function in any language you've loaded; this is always specified by the function's `lang` parameter. If you omit that parameter, the function will be called in the current default language.\n\nExample:\n\n```python\n>>> from lingua_franca import load_languages, \\\n set_default_lang, parse\n>>> load_languages(['es', 'en'])\n>>> parse.extract_number(\"uno\")\n1\n>>> parse.extract_number(\"one\")\nFalse\n>>> parse.extract_number(\"one\", lang='en')\n1\n>>> set_default_lang('en')\n>>> parse.extract_number(\"uno\")\nFalse\n>>> parse.extract_number(\"one\")\n1\n```\n\nIn some languages, certain parameters have no effect, either because\nthose parameters do not apply, or because the localization is not complete.\n\nIt's important to remember that Lingua Franca is in alpha. Support for a\nparticular language may be inconsistent, and one language's version of a\ncomplex function might be outdated compared with another.\n\nNew functionality usually starts in the languages spoken by major\ncontributors. If your language's functions are lacking, we'd love your help\nimproving them! (See below, \"Contributing.\")\n\n## Contributing to this project\n\nWe welcome all contributions to Lingua Franca. To get started:\n\n### 0. Sign a Contributor Licensing Agreement\n\nTo protect yourself, the project, and users of Mycroft technologies, we require a Contributor Licensing Agreement (CLA) before accepting any code contribution. This agreement makes it crystal clear that, along with your code, you are offering a license to use it within the confines of this project. You retain ownership of the code, this is just a license.\n\nYou will also be added to [our list of excellent human beings](https://github.com/MycroftAI/contributors)!\n\nPlease visit https://mycroft.ai/cla to initiate this one-time signing.\n\n### 1. Setup a local copy of the project\n\n1. [Fork the project](https://help.github.com/articles/fork-a-repo/) to create your own copy.\n\n2. Clone the repository and change into that directory\n\n```bash\ngit clone https://github.com/your-username/lingua-franca/\ncd lingua-franca\n```\n\n3. Setup a lightweight virtual environment (venv) for the project. This creates an isolated environment that can have it's own independent set of installed Python packages.\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\n```\n\n To exit the venv you can run `deactivate` or close the terminal window.\n\n4. Install the package and it's dependencies\n\n```bash\npip install wheel\npython -m pip install .\npip install pytest\npython setup.py install\n```\n\n5. To check that everything is installed correctly, let's run the existing test-suite.\n\n```bash\npytest\n```\n\n### 2. Have a look at the project's structure\n\nThe package's layout is described in `project-structure.md`, along with some important notes. It's pretty\nintuitive, but uniform file and function names are important to Lingua Franca's operation.\n\n### 3. Writing tests\n\nWe utilize a Test Driven Development (TDD) methodology so the first step is always to add tests for whatever you want to add or fix. If it's a bug, we must not have a test that covers that specific case, so we want to add another test. If you are starting on a new language then you can take a look at the tests for other languages to get started.\n\nTests are all located in `lingua_franca/test`.\nEach language should have two test files:\n\n- `test_format_lang.py`\n- `test_parse_lang.py`\n\n### 4. Run tests to confirm they fail\n\nGenerally, using TDD, all tests should fail when they are first added. If the test is passing when you haven't yet fixed the bug or added the functionality, something must be wrong with the test or the test runner.\n\n```bash\npytest\n```\n\n### 5. Write code\n\nNow we can add our new code. There are three main files for each language:\n\n- `common_data_lang.py` \n Common data that can be used across formatting and parsing such as dictionaries of number names.\n- `format_lang.py` \n All formatting functions for this language.\n- `parse_lang.py` \n All parsing functions for this language.\n\nSince we have already written our unit tests, we can run these regularly to see our progress.\n\n### 6. Document your code\n\nDocument code using [Google-style docstrings](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html). Our automated documentation tools expect that format. All functions and class methods that are expected to be called externally should include a docstring. (And those that aren't should be [prefixed with a single underscore](https://docs.python.org/3/tutorial/classes.html#private-variables).\n\n### 7. Try it in Mycroft\n\nLingua Franca is installed by default when you install Mycroft-core, but for development you generally have this repo cloned elsewhere on your computer. You can use your changes in Mycroft by installing it in the Mycroft virtual environment.\n\nIf you added the Mycroft helper commands during setup you can just use:\n\n```bash\nmycroft-pip install /path/to/your/lingua-franca\n```\n\nOtherwise you need to activate that venv manually:\n\n```bash\ncd ~/mycroft-core\nsource venv-activate.sh\npip install /path/to/your/lingua-franca\n```\n\nNow, when talking with Mycroft, it will be using your development version of Lingua Franca.\n\n### 8. Commit changes\n\nMake commits in logical units, and describe them thoroughly. If addressing documented issue, use the issue identifier at the very beginning of each commit. For instance:\n\n```bash\ngit commit -m \"Issues-123 - Fix 'demain' date extraction in French\"\n```\n\n### 9. Submit a PR\n\nOnce your changes are ready for review, [create a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request).\n\nLike commit messages, the PR title and description should properly describe the changes you have made, along with any additional information that reviewers who do not speak your language might need to understand.\n\n### 10. Waiting for a review\n\nWhile you wait for a review of your contribution, why not take a moment to review some other pull requests? This is a great way to learn and help progress the queue of pull requests, which means your contribution will be seen more quickly!\n\n## Credits\n\nThough it is now a standalone package, Lingua Franca's codebase was a spinoff from Mycroft-core. In addition to those represented in Lingua Franca's git log, a great many people contributed to this code before the spinoff. \n\nAlthough all are listed in MycroftAI's [List of Excellent People](https://github.com/MycroftAI/contributors), it seems proper to acknowledge the specific individuals who helped write *this* package, since they are no longer represented in `git log`. \n\nTo the best of the maintainers' knowledge, all of the \"lost\" contributors are listed in `pre-spinoff-credits.md`. Names are listed as they appeared in `git log`, or as they are known to the Mycroft community. \n\nThose who've contributed since the spinoff are, of course, in Lingua Franca's `git log` and the GitHub \"Contributors\" pane. All contributors are on the List of Excellent People, regardless of when they contributed. \n\nIf you contributed to the original code, and your name is missing from `pre-spinoff-credits.md`, please inform a maintainer or file an issue, so we can give credit where credit is due!\n\n",
"bugtrack_url": null,
"license": "Apache2.0",
"summary": "OpenVoiceOS's multilingual text parsing and formatting library",
"version": "0.4.7",
"project_urls": {
"Homepage": "https://github.com/OpenVoiceOS/ovos-lingua-franca"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "01d04006720ecfe1508efbd55c875ed6b71f078ff5a0514d1026b482339aab5f",
"md5": "16054a46315e45af399eda35f791f34b",
"sha256": "69dde895f3b9fb66c3756fc5d66a48a0ab9683f487e38eeb64ce533461a5bb49"
},
"downloads": -1,
"filename": "ovos_lingua_franca-0.4.7-py3-none-any.whl",
"has_sig": false,
"md5_digest": "16054a46315e45af399eda35f791f34b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 406864,
"upload_time": "2023-04-05T10:54:23",
"upload_time_iso_8601": "2023-04-05T10:54:23.399538Z",
"url": "https://files.pythonhosted.org/packages/01/d0/4006720ecfe1508efbd55c875ed6b71f078ff5a0514d1026b482339aab5f/ovos_lingua_franca-0.4.7-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-04-05 10:54:23",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "OpenVoiceOS",
"github_project": "ovos-lingua-franca",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "ovos-lingua-franca"
}