Metadata-Version: 2.4
Name: translation-finder
Version: 3.8.0
Summary: A translation file finder used in Weblate.
Home-page: https://weblate.org/
Download-URL: https://github.com/WeblateOrg/translation-finder
Author: Michal Čihař
Author-email: Michal Čihař <michal@weblate.org>
License-Expression: GPL-3.0-or-later
Project-URL: Documentation, https://docs.weblate.org/
Project-URL: Download, https://github.com/WeblateOrg/translation-finder
Project-URL: Funding, https://weblate.org/donate/
Project-URL: Homepage, https://weblate.org/
Project-URL: Issue Tracker, https://github.com/WeblateOrg/translation-finder/issues
Project-URL: Source Code, https://github.com/WeblateOrg/translation-finder
Project-URL: Twitter, https://twitter.com/WeblateOrg
Keywords: i18n,l10n,gettext,weblate,translate
Platform: any
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Software Development :: Internationalization
Classifier: Topic :: Software Development :: Localization
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Description-Content-Type: text/x-rst
License-File: LICENSE
Requires-Dist: charset-normalizer<4.0,>2.0
Requires-Dist: weblate-language-data>=2026.11
Dynamic: download-url
Dynamic: license-file

Translation Finder
==================

.. image:: https://img.shields.io/badge/website-weblate.org-blue.svg
    :alt: Website
    :target: https://weblate.org/

.. image:: https://hosted.weblate.org/widgets/weblate/-/svg-badge.svg
    :alt: Translation status
    :target: https://hosted.weblate.org/engage/weblate/?utm_source=widget

.. image:: https://bestpractices.coreinfrastructure.org/projects/552/badge
    :alt: CII Best Practices
    :target: https://bestpractices.coreinfrastructure.org/projects/552

.. image:: https://img.shields.io/pypi/v/translation-finder.svg
    :target: https://pypi.org/project/translation-finder/
    :alt: PyPI package

.. image:: https://readthedocs.org/projects/weblate/badge/
    :alt: Documentation
    :target: https://docs.weblate.org/

Translation file discovery library used by `Weblate`_ to identify translation files and their configuration in source repositories.

Discovery can operate on file listings alone or inspect the filesystem when more accurate detection is needed, such as determining file encoding or distinguishing formats with similar syntax.

.. image:: https://s.weblate.org/cdn/Logo-Darktext-borders.png
   :target: https://weblate.org/
   :alt: Weblate
   :height: 55px

Maintained by `Weblate <https://weblate.org/>`_ — a privacy-respecting localization platform built on open-source foundations.

Usage
-----

It can be used from Python:

.. code-block:: pycon

   >>> from translation_finder import discover
   >>> from pprint import pprint
   >>> results = discover("translation_finder/test_data/")
   >>> len(results)
   40
   >>> pprint(results[0].match)
   {'file_format': 'aresource',
    'filemask': 'app/src/res/main/values-*/strings.xml',
    'name': 'android',
    'template': 'app/src/res/main/values/strings.xml'}
   >>> pprint(results[1].match)
   {'file_format': 'po',
    'filemask': 'locales/*.po',
    'name': 'translation',
    'new_base': 'locales/messages.pot'}

Additional information about discovery can be obtained from meta attribute:

.. code-block:: pycon

   >>> pprint(results[0].meta)
   {'discovery': 'TransifexDiscovery', 'origin': 'Transifex', 'priority': 500}
   >>> pprint(results[22].meta)
   {'discovery': 'GettextDiscovery', 'origin': None, 'priority': 1000}


Or command line:

.. code-block:: console

   $ weblate-discovery translation_finder/test_data/
   == Match 1 (Transifex) ==
   file_format    : aresource
   filemask       : app/src/res/main/values-*/strings.xml
   name           : android
   template       : app/src/res/main/values/strings.xml
   ...

   == Match 7 ==
   file_format    : po
   filemask       : locales/*.po
   new_base       : locales/messages.pot

Non-printable characters in command-line results are displayed as visible
escapes (for example, ``\n`` and ``\x1b``). The Python API returns the original
values unchanged.

Discovery limits
----------------

The CLI accepts nonnegative integer limits. Zero permits no work for that
budget. Defaults are:

* ``--max-candidates``: 4096 generated candidates across all backends.
* ``--max-results``: 4096 returned matches.
* ``--max-new-base-checks``: 65536 new-base lookups across all backends.
* ``--max-masks-per-path``: 32 generated masks per path.
* ``--sniff-max-bytes``: 67108864 bytes (64 MiB) sampled across the run.
* ``--sniff-max-files``: 512 content-sniffing file attempts across the run.

For example, ``weblate-discover --max-results 10000 translations/`` raises
only the result limit. ``weblate-discover --unlimited translations/`` disables
all six discovery budgets; it cannot be combined with individual limit options.
Internal parser safeguards and per-result format and encoding sampling limits
remain active.

The CLI prints collected matches to stdout, including partial results. If
candidate, result, new-base, or per-path mask limits cause truncation, it prints
one warning with the limit reasons to stderr and exits with status 3. Complete
discovery exits with status 0; invalid arguments exit with status 2.
Sniff-budget exhaustion uses best-effort detection and does not itself report
truncation.

Python callers can import ``DiscoveryLimits`` from ``translation_finder.api``
and pass it as the keyword-only ``limits`` argument to ``discover()``. Defaults
match the CLI; a field set to ``None`` disables that limit, and
``DiscoveryLimits.unlimited()`` disables all six. Negative values raise
``ValueError``. Inspect ``results.truncated`` and ``results.limit_reasons`` for
truncation; high-level discovery does not emit Python warnings.

Custom discovery backends
-------------------------

Custom ``BaseDiscovery`` implementations return ``DiscoveryCandidate`` objects
from ``get_masks()``. Each candidate associates the result with the paths which
actually generated it, allowing content detection to inspect the group without
expanding its wildcard mask again:

Candidate generation, new-base resolution, and returned results are bounded
across each discovery run. The returned ``DiscoveryResults`` object behaves as
a list and exposes ``truncated`` and ``limit_reasons`` attributes. These report whether a safety limit made results potentially
incomplete, without emitting a Python warning.

Calling ``get_masks()`` directly is a low-level interface with only the
per-path mask limit. Use ``discover()`` for run-wide resource bounds and
structured limit status.

.. code-block:: python

   from translation_finder.discovery.base import BaseDiscovery
   from translation_finder.discovery.result import DiscoveryCandidate


   class CustomDiscovery(BaseDiscovery):
       def get_masks(self, *, eager=False, hint=None):
           for path in self.filter_files():
               yield DiscoveryCandidate({"filemask": "locale/*.json"}, [path])

.. _Weblate: https://weblate.org/
