md2star.i18n module

Message catalogues for the parts of md2star a person reads.

Two surfaces speak to a human: the CLI’s diagnostics and the local GUI. They were English-only, which for a tool whose documentation ships in two languages was an odd place to stop.

The machinery is os_helper.Catalog, the loader shared across the AI Helpers suite — stdlib gettext underneath, with .po sources under md2star/data/locales/<lang>/LC_MESSAGES/ compiled to the .mo it reads. No Babel, no new dependency, and no build-time toolchain either: os_helper.compile_catalogs writes the .mo itself, because requiring GNU gettext’s msgfmt to be installed would make a translated interface harder to ship than the feature is worth.

What stays here is the policy, which is md2star’s and not the suite’s.

The CLI does not follow your shell locale, on purpose. It answers to MD2STAR_LANG and nothing else. A converter that silently changes the language of its own output because LANG says fr_FR is a converter that breaks every script grepping it, and the diagnostics are as much a machine interface as a human one. The GUI does negotiate Accept-Language, because a browser asking for French is a person asking, not an environment variable.

The default is English, not French. Every other member of the suite serves a French GUI by default; md2star’s CLI prints the language its caller asked for and nothing else, so with no MD2STAR_LANG the answer must be the source text. That is why this module keeps a policy layer rather than letting the call sites reach for Catalog directly.

A message with no translation falls back to the English source — gettext’s own behaviour — so a partial catalogue leaves an interface that is partly translated rather than one that is broken.

Author

[Warith HARCHAOUI](https://linkedin.com/in/warith-harchaoui/)

md2star.i18n.DOMAIN = 'md2star'

The gettext domain, and therefore the .mo file’s stem.

md2star.i18n.ENV_VAR = 'MD2STAR_LANG'

The one environment variable the CLI listens to. Deliberately ours rather than LANG: see the module docstring.

md2star.i18n.SOURCE_LANGUAGE = 'en'

The language the sources are written in, so it never needs a catalogue.

md2star.i18n.ambient()[source]

The CLI’s catalogue, from ENV_VAR alone.

Return type:

NullTranslations

md2star.i18n.available()[source]

Languages with a compiled catalogue, sorted. English is implicit.

Returns:

The translated languages only. English is excluded even though os_helper.Catalog.languages includes it: it has no catalogue to be “available”, and every caller here reads this as “languages somebody wrote a file for”.

Return type:

list of str

md2star.i18n.candidates(tag)[source]

A language tag plus its base, so fr-CA finds the fr catalogue.

A thin alias for os_helper.language_candidates(), kept because this name is what md2star’s own call sites and tests already use.

Parameters:

tag (str | None)

Return type:

list[str]

md2star.i18n.catalog()[source]

The suite’s shared catalogue loader, bound to this package.

default_language is the source language, which is what makes an absent MD2STAR_LANG print English rather than French. The rest of the suite defaults its GUIs to French; a CLI that answers to its caller cannot.

Return type:

Catalog

md2star.i18n.gettext(message)[source]

Translate message for the CLI’s ambient language.

Named to read as _() at the call site:

from .i18n import gettext as _
print(_("Wrote: %s") % path)
Parameters:

message (str)

Return type:

str

md2star.i18n.locales_dir()[source]

Where the compiled catalogues live, inside the installed package.

Return type:

Path

md2star.i18n.negotiate(header)[source]

Best language from an Accept-Language header, or None.

Honours q weights and falls back to a base language, so a browser asking for fr-CA;q=0.9, en;q=0.8 gets the fr catalogue. Returns None when the best match is English or when nothing offered has a catalogue — both of which mean “leave the source text alone”.

Parameters:

header (str | None)

Return type:

str | None

md2star.i18n.ngettext(singular, plural, n)[source]

Plural-aware lookup — n picks the form the language actually uses.

Parameters:
Return type:

str

md2star.i18n.reset_cache()[source]

Forget every resolved catalogue, so the next lookup reads afresh.

The language is resolved from the environment on each call, but the catalogue behind it is cached — twice, once for the handle and once per language inside it. A test that writes a new .po mid-run, or changes which languages exist, needs both cleared or it reads the old answer. Changing MD2STAR_LANG alone does not: that is read every time.

Return type:

None

md2star.i18n.translator(tag=None)[source]

The catalogue for tag, or a pass-through when there is none.

A tag with no catalogue yields a pass-through rather than a fallback language: here “no catalogue” means English, which is the source, so returning each message unchanged is exactly the right answer.

Parameters:

tag (str | None)

Return type:

NullTranslations