An unofficial Python port of vue-i18n. Not affiliated with or endorsed by intlify; vue-i18n is © kazuya kawaguchi and contributors, MIT licensed.
Same JSON message files, same API, same behaviour — in Python. The point is a Vue front end and a Python back end reading one set of translations and producing the same strings from them.
import json
from vue_i18n import create_core_context, translate
ctx = create_core_context(
locale="sl",
fallback_locale="en",
messages={ # the files your front end already loads
"sl": json.load(open("locales/sl.json")),
"en": json.load(open("locales/en.json")),
},
)
translate(ctx, "hello", {"name": "Jure"}) # 'Zdravo Jure'
translate(ctx, "trips", 5) # plural form for 5docs.velis.si/vue-i18n-python is the manual.
| Why this exists, and who should not use it | Rationale |
| Installing it and the call shapes | Getting started |
| The one thing that surprises people | Plural rules |
| Where it deliberately differs from vue-i18n | Differences |
| Every public function | API reference |
Message files are ordinary vue-i18n resources: {named} placeholders, {0} positional values,
a | b | c plurals, @:linked messages, @.upper: modifiers, {'@'} literals. Nothing asks you
to migrate a file or learn a syntax, and vue-i18n-extract and the rest of the toolchain keep
working.
Option names are vue-i18n's, in snake_case: fallbackLocale is fallback_locale, missingWarn is
missing_warn.
t("cart.emty") does not fail — it renders the key and waits for a customer to find it. The
bundled checker finds it first, on both ends of the project:
python -m vue_i18n.check locales/ --source backend/ --source frontend/srcBroken @:links, messages that will not compile, keys one locale is missing, keys the code asks for
and no locale has. Python is parsed; .vue and .ts are pattern-matched, which is approximate and
labelled so — and still more than xgettext, which cannot open a .vue file at all.
Faithful enough that the claim is checked rather than asserted. Every part of the port is recorded against the real thing and replayed on every test run:
| corpus | what it pins |
|---|---|
conformance/translate.json |
57 translate() calls against @intlify/core-base itself |
conformance/render.json |
74 messages rendered by real vue-i18n |
conformance/compile.json |
128 messages: ASTs, error codes, error messages, source locations |
conformance/resolve.json |
200 key-path resolutions |
conformance/fallback.json |
374 fallback chains |
conformance/display.json |
1612 values through JavaScript's String() semantics |
The recordings are generated by running upstream, never written by hand —
scripts/conformance/README.md says how to regenerate them.
This port tracks vue-i18n's released versions, never a pre-release. Upstream is a git submodule
pinned to the version being tracked, so "which vue-i18n does this match" is answered by a checkout
rather than by a claim. UPSTREAM.md records the pin, maps every module to the upstream file it
came from, and holds the procedure for moving to a new release.
Some differences are forced by the platform: JavaScript strings are UTF-16 and Python's are not,
Intl does not exist here so d() and n() go through babel with different CLDR data, and a
Python int stays exact past 2^53.
Others are chosen, and each one is written down in PROGRESS.md with the reasoning, a comment at
the site and a test that asserts it. GAPS.md lists what is knowingly missing.
If your Vue application already passes pluralRules to createI18n, pass the same rule here and
nothing changes. A rule is (choice, choices_length) -> index, the same signature as in
JavaScript, so it transcribes directly:
def south_slavic(choice, choices_length, _org=None):
if choices_length == 2:
return 0 if choice == 1 else 1
...
ctx = create_core_context(..., plural_rules={"sl": south_slavic})
translate(ctx, "trips", 103) # '103 povezave' - the fourth form, as in the browserIf you pass no rule, you get vue-i18n's default, and that default ignores the locale: two forms
mean singular/plural, and anything more clamps at index 2, so a fourth or fifth form is unreachable
in any language. This port reproduces that rather than quietly improving on it — the same message
with no rule renders 3 povezavi, 5 povezavi and 105 povezavi — the count interpolates, the
ending is what sticks — here and in the browser alike.
vue_i18n.plurals is there if you would rather not hand-write the rule. It is opt-in; the
runtime never reaches for it. It carries CLDR rules for 224 locales, an explicit zero form that
CLDR does not have, and a ladder for messages with fewer forms than the locale has categories. Note
that it will not agree with a hand-written rule in every case — if your front end has one, port that
one, and keep the two ends identical.
Early, and honest about it — see PROGRESS.md for what exists and GAPS.md for what does not.
MIT