# translate-python and its five translation providers

> terryyin/translate-python is a small Python library and command line tool that wraps several online translation services behind one Translator object, with MyMemory as the default so that no key is required. It is convenient for scripts and one-off commands, and its pinning of a LibreTranslate client and its lack of a release history are the two things to look at before you build on it.

**terryyin/translate-python** — Online translation as a Python module & command line tool. No key, no authentication needed.

- Repository: https://github.com/terryyin/translate-python
- Stars: 759 · Forks: 152
- Language: Python
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/terryyin-translate-python

## One interface over five online services

The project describes itself as online translation as a Python module and command line tool, with no key and no authentication needed. That last clause is about the default, and the default is MyMemory, which is a public translation service that does not require credentials.

Underneath that, the README lists the providers it integrates with: the Microsoft Translation API, the Translated MyMemory API, LibreTranslate, DeepL's free and pro APIs, and the Yandex Translate API. The stated reason to use the tool is to make translations in a simple way without the need of bigger effort, and to be usable as a translation tool like command line.

That framing sets expectations correctly. This is a convenience wrapper, not a translation engine. It does not translate anything itself; it assembles a request, signs it if the provider needs a key, sends it over HTTP, and hands back the provider's answer. The quality of the output, the rate limits, the daily quotas, and the uptime are all properties of the provider you select.

The people who benefit are those who need to translate occasionally and do not want to learn five provider APIs, or who want a single call in a script that works without credentials, or who want to try a second provider when the first one gives a bad answer. The people who should not reach for it are those with a volume requirement, because nothing in the documentation addresses throughput, caching, or what happens when a provider throttles you.

## translate-cli, its flags, and the config file that only the CLI reads

The command line entry point is translate-cli, and the usage is short enough to remember:

```bash
   $ translate-cli -t zh "This is a pen."
```

By default it prints the translation, a separator, and which provider produced it, which is the useful part when you are comparing providers. There is a flag for output only, -o or --output_only, which prints just the translated text, and that is the form you want in a script or a shell pipeline.

The full option set is documented by asking the tool itself:

```bash
    $ translate-cli --help
    Usage: __main__.py [OPTIONS] TEXT...

      Python command line tool to make online translations

      Example:

           $ translate-cli -t zh the book is on the table

      Available languages:

           https://en.wikipedia.org/wiki/ISO_639-1
           Examples: (e.g. en, ja, ko, pt, zh, zh-TW, ...)
```

The options themselves cover the source language with -f and --from, which defaults to autodetect, the target with -t and --to, the provider with -p and --provider, defaulting to mymemory, a --secret_access_key for providers that need an OAuth token, and -r and --region for API calls that require a region. Language codes follow the ISO 639-1 list.

Defaults can be persisted in a config file at ~/.python-translate.cfg, which holds a DEFAULT section with from_lang, to_lang, provider and secret_access_key. The README is explicit about one boundary: the cfg is not for use as a Python module. The file belongs to the command line tool, and the module reads its arguments from the code.

There is also a wizard, translate-cli --generate-config-file, which prompts for the source language, target language, provider and secret access key and writes the file for you.

## The Translator object and the provider-specific arguments

As a module, the entry point is the Translator class, and the basic case is three lines:

```python
   In [1]: from translate import Translator
   In [2]: translator = Translator(to_lang="zh")
   In [3]: translation = translator.translate("This is a pen.")
```

The result is usually a unicode string, which is worth noting because it means the return type is not a strict contract and a caller that assumes otherwise may mishandle a provider that returns a different shape.

Switching providers is a constructor argument, and the provider-specific settings are passed alongside it:

```python
    In [1]: from translate import Translator
    In [2]: to_lang = 'zh'
    In [3]: secret = '<your secret from Microsoft or DeepL>'
    In [4]: translator = Translator(provider='<the name of the provider, eg. microsoft or deepl>', to_lang=to_lang, secret_access_key=secret)
    In [5]: translator.translate('the book is on the table')
```

Two providers need extra arguments and both are documented separately. DeepL's pro API needs an additional parameter named pro on the Translator object, set to True, with the pro authentication key used as the secret_access_key:

```python
    In: translator = Translator(provider='deepl', to_lang=to_lang, secret_access_key=secret, pro=True)
```

Yandex supports both API key and IAM token authentication, where the IAM token path needs the is_iam parameter set to True, and you may also need to provide a folder_id for your Yandex Cloud project:

```python
    In: translator = Translator(provider='yandex', to_lang=to_lang, secret_access_key='your_api_key', folder_id='your_folder_id')
    In: translator = Translator(provider='yandex', to_lang=to_lang, secret_access_key='your_iam_token', folder_id='your_folder_id', is_iam=True)
```

The pattern across all three is the same: a provider name, a credential, and occasionally one more switch. The interface is stable, but the constructor grows a small argument per provider, which is the cost of a single entry point over five different authentication schemes.

## The pinned LibreTranslate client and the dependency floor

The runtime requirements are short, and one of them is pinned to an exact version:

```
click
lxml
requests
libretranslatepy==2.1.1
```

That pin is the detail to notice. libretranslatepy is locked to 2.1.1 with no upper or lower range, so a fresh install gets that version and that version only, and it is an old client for a service that has moved on since. If you point the library at a LibreTranslate server whose API has moved on, the client is the part that will not adapt, and you cannot upgrade it without either patching the requirement or dropping the LibreTranslate provider.

The other three requirements are unpinned: click for the command line interface, requests for the HTTP calls, and lxml for parsing. That is a reasonable split for a small tool, and it also means the tool inherits whatever behaviour those libraries have in the version your resolver picks.

The Makefile shows how the development environment is put together, and it contains a detail that tells you about the target audience. There is a check for whether Python is 3.11 or newer, and on those versions the pip-install target adds the --break-system-packages flag, otherwise it does not. In other words the project explicitly supports both older and current Python, and works around the newer pip behaviour of refusing to install into a system environment.

The other targets are conventional: lint runs pre-commit, cov runs coverage and pushes to codecov, cov-report produces an HTML coverage report, and test depends on installing the build requirements and then running py.test -vv -s.

## The version number is parsed out of the changelog at build time

The packaging is unconventional in a way that is easy to miss. setup.py does not declare a version constant. It opens CHANGES.rst, walks the lines, and applies a regular expression to find the first line that looks like a version number, using the pattern for a numeric version with an optional patch component. Whatever it finds becomes the package version.

There is a second mechanism alongside it. A save_version function reads translate/version.py, finds the __version__ assignment with another regular expression, and rewrites the file with the version it just parsed. A custom setuptools Command class, VersionCommand, prints the version, and its description is simply to show library version.

So the changelog is the single source of truth for the version, and the generated version.py is kept in step. That is a defensible design for a project with one maintainer, since it removes a place where the version can drift, but it does mean the build reads a documentation file to decide what it is packaging.

One more inconsistency is worth flagging. The description string in setup.py still says this is a command line translator with google translate behind it, while the README lists the Microsoft, MyMemory, LibreTranslate, DeepL and Yandex providers and does not mention Google. The package metadata is stale, which is harmless to users of the API but is the kind of thing that makes a reader wonder how much else in the packaging is current.

The release flow is handled by make release, which depends on the build, and the build depends on the tests. It tags and pushes using the version command, and the Makefile notes that a tag push triggers the GitHub Actions release workflow to publish to PyPI.

## Contributing, testing, and the odd files in the tree

The contributing guide is specific enough to follow. Fork the repository on GitHub, make a branch off master and commit your changes to it, install the development requirements with pip install -r requirements-dev.txt, install pre-commit with pre-commit install, run the tests with py.test -vv -s, and open a pull request. There is an optional step for an isolated environment, which the guide suggests by installing nixOS and running nix-shell --pure under the project folder.

That nix option is not decorative. The tree carries flake.nix, flake.lock and shell.nix, so the project has a reproducible shell available, which is a better answer to dependency drift than a loose requirements file.

The rest of the top level tells a similar story about a small, tooled project. There is a .pre-commit-config.yaml, a pytest.ini, a .coveragerc, a Makefile, setup.cfg, setup.py, MANIFEST.in and separate requirements files for development and for building. Documentation is handled by .readthedocs.yaml and a docs/ directory, with the published docs at translate-python.readthedocs.io. There is a sample-python-translate.cfg showing what a config file looks like, and a tests/ directory.

And then there are three files that are not typical of the project type: AGENTS.md, CLAUDE.md, and a .cursor/ directory alongside a .cursorrules file. Those are instructions for coding agents, and their presence in the tree is a reasonable signal about how the project now expects contributions to be prepared, if nothing else.

The repository also keeps a .travis.yml, although the visible build badge points at the Travis service, so the CI setup is a mix of eras.

## Where this is the wrong tool

The honest failure mode of a wrapper like this is not a wrong answer, it is a slow one. A single translate call is one HTTPS request to a third party. In a loop over ten thousand strings, that is ten thousand requests against a free or metered endpoint, and the README documents no batching, no caching, no connection reuse, and no handling of provider rate limits or of retry-after responses. If your workload is bulk content, the tool is going to hand you the provider's throttling behaviour with no layer in between.

The second failure mode is the pinned client. If LibreTranslate is your target, the exact pin on libretranslatepy 2.1.1 is a fixed point in time that you cannot move without changing the requirements, and that is a problem whenever the server side moves.

The third is provider opacity. A translator that returns a unicode string usually hides which provider answered, which means a pipeline that quietly degrades from a paid provider to a free one, or from one model to another, is hard to notice. The command line output does name the provider, and for the module path the README does not document how to retrieve it, so if provider visibility matters to you, that is a question to ask before you commit to this library.

The alternative for anything beyond occasional use is to call the provider API directly. You would use requests, which is already a dependency here, sign the request the way that provider requires, and own the retry, the batching, the caching and the error handling. What you give up is the single interface across five providers, the credential handling that the Translator object already does, and the translate-cli command that makes a quick shell check a one-liner. For a script that translates a sentence or a hundred strings, translate-python is the shorter path. For a service, the direct call is the one you will end up writing anyway.

## Conclusion

Adopt translate-python when you want one small interface in front of several online translation providers, need a translator that works with no credentials for occasional use, and value the translate-cli command for shell pipelines and quick checks. Do not adopt it for a high-volume production pipeline, since the README documents no caching, no batching and no rate limit handling, and the requirements pin an old LibreTranslate client. Verify first which provider your plan allows and what your quota looks like, and check the pinned libretranslatepy version against the LibreTranslate server you point it at before you rely on that provider.

## FAQ

### How do I install translate-python and translate a string from the command line?

Install it with pip install translate, or download the source and run python setup.py install, prefixing sudo if you hit a problem. Then run translate-cli -t zh "This is a pen.", which prints the translation and the provider that produced it, and use the -o flag to print only the translation.

### Which translation providers does translate-python support and do I need an API key?

It integrates with the Microsoft Translation API, the Translated MyMemory API, LibreTranslate, DeepL's free and pro APIs, and the Yandex Translate API. The default provider is mymemory, which needs no key or authentication, and other providers take a secret_access_key.

### How do I use translate-python as a Python module?

Import Translator, construct it with a target language and optionally a provider and secret_access_key, and call translate on the text. The result is usually a unicode string, and DeepL's pro API needs pro=True while the Yandex IAM token path needs is_iam=True and a folder_id.

### Can I store my translate settings in a config file?

Yes for the command line tool, in ~/.python-translate.cfg with a DEFAULT section holding from_lang, to_lang, provider and secret_access_key, or you can run translate-cli --generate-config-file to be prompted. The README states the cfg is not for use as a Python module.

## Sources

- [Issues](https://github.com/terryyin/translate-python/issues)
- [License: MIT](https://github.com/terryyin/translate-python/blob/master/LICENSE)
- [README](https://github.com/terryyin/translate-python/blob/master/README.md)
- [terryyin/translate-python on GitHub](https://github.com/terryyin/translate-python)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/terryyin-translate-python
