Skip to main content

Noctalia i18n Core

简体中文

Noctalia i18n Core is a read-only Python client for project progress, current translations, and changes from Noctalia Translate. Storage, scheduling, delivery, and application policy belong to the caller.

Capabilities

  • Read project details, translation context, and project-wide and per-locale progress.
  • Read current translations as a complete catalog, exact-key results, or text-search results.
  • Query missing translations and translations that need review in a selected locale.
  • List dot-separated translation keys and filter them by hierarchy prefix.
  • Read complete changes for selected keys in one locale.
  • Lazily read the project-wide change stream with locale, time, and anchor boundaries.
  • Read validated change pages with a durable cursor for resumable scans.
  • Retry temporary connection, timeout, rate-limit, and server failures.
  • Use a caller-owned requests.Session when connection policy must be configured by the application.

Project structure

noctalia_i18n_core/
├── client.py   # Website requests and response validation
└── models.py   # Normalized project and change values

Installation

uv add noctalia-i18n-core

Or with pip:

pip install noctalia-i18n-core

Usage

Create a client

from noctalia_i18n_core import NoctaliaClient

with NoctaliaClient("noctalia", timeout=30) as client:
    key = "settings.widgets.settings.scroll-repeat.label"
    value = client.translations(key, locales=("zh-Hans",))[key]["zh-Hans"]
    changes = client.changes(key, locale="zh-Hans")

    print(value)
    print(changes[0].occurred_at if changes else "No changes")

The client retries temporary failures and closes the session it creates. Pass a configured requests.Session when the application owns connection settings such as proxies or retry policy; caller-owned sessions are used without modification.

Project details and progress

project() makes one project request and returns the public name, description, translation context, and current progress. Project and locale progress use the integer percentage shown by the website. The review count identifies translations whose English source changed after that translation was last saved.

project = client.project()

print(project.name, project.key_count, project.language_count, project.progress)
for locale in project.locales:
    print(
        locale.code,
        locale.progress,
        locale.missing_count,
        locale.review_count,
    )

Current translations

translations() reads one or more exact keys in website-sized batches. Its key-first result preserves the requested key and locale order. A requested key remains present with an empty mapping when no selected locale has a value.

values = client.translations(
    "settings.widgets.settings.scroll-repeat.description",
    "settings.widgets.settings.scroll-repeat.label",
    locales=("zh-Hans", "en"),
)

catalog() makes one complete export request and returns {key: {locale: value}}. It is intended for callers that need every current translation.

catalog = client.catalog()
source_text = catalog["settings.widgets.settings.scroll-repeat.description"]["en"]

Text search

search_translations() searches the key and current value in search_locale, follows all result pages, and reads the requested result locales for the matching keys. If locales is omitted, the result contains only search_locale.

matches = client.search_translations(
    "确认",
    search_locale="zh-Hans",
    locales=("zh-Hans", "en"),
)

Missing translations and reviews

missing() returns source entries without a current translation in one locale. reviews() returns entries whose English source changed after the translation was last saved. Both results include the key, locale, current source, and translation page; reviews additionally include the previous source. Both queries accept query to filter their results.

missing = client.missing("fr", query="scroll")
reviews = client.reviews("fr")

for item in missing:
    print(item.key, item.source, item.translation_url)

for review in reviews:
    print(review.key, review.previous_source, review.source)

Translation keys

keys() makes one key-tree request and returns the complete key list. A prefix matches a complete dot-separated hierarchy rather than an arbitrary string prefix.

widget_keys = client.keys(prefix="settings.widgets")

Changes for selected keys

changes() reads the complete changes for one or more exact keys in one locale. The returned tuple is ordered from newest to oldest; multiple key results are merged in that order.

changes = client.changes(
    "settings.widgets.settings.scroll-repeat.description",
    locale="zh-Hans",
)
for change in changes:
    print(change.occurred_at, change.action, change.new_value)

Project change stream

iter_changes() lazily reads the project-wide change stream in the order supplied by the website. since and until are inclusive, timezone-aware boundaries and are normalized to UTC. locale restricts the stream to one locale.

from datetime import UTC, datetime

recent = client.iter_changes(
    locale="zh-Hans",
    since=datetime(2026, 8, 1, tzinfo=UTC),
)
for change in recent:
    print(change.key, change.action)

after is a website change ID. The client confirms the anchor before yielding a result and raises RuntimeError when it is absent. on_progress receives the completed page number and current total page count after each request.

change_pages() exposes the same stream as immutable ChangePage values. start_page selects a one-based page. cursor is an opaque resume position stored by the caller; the client discards that position and newer records before continuing with older pages.

page = next(client.change_pages(start_page=1))
print(page.number, page.total_pages, page.cursor)

API reference

NoctaliaClient

NoctaliaClient(project, *, timeout, session=None)

project is the website project identifier. timeout is a positive finite number of seconds applied to each attempt. By default, temporary connection, timeout, rate-limit, and server failures are retried three times with backoff. session may be a caller-owned requests.Session; its transport policy is preserved and the client does not close it.

Member Result
slug The project identifier passed to the constructor
translation_url(key, locale) Translation page for one key and locale
project() Project details and current translation progress
keys(*, prefix=None) tuple[str, ...] of complete or prefix-matched keys
catalog() dict[str, dict[str, str]] containing the complete current catalog
translations(key, *keys, locales=None) Key-first exact translations
search_translations(query, *, search_locale, locales=None) Key-first translations for text matches
missing(locale, *, query=None) Missing translations with their source text
reviews(locale, *, query=None) Translations needing review in one locale
changes(key, *keys, locale) Newest-first exact-key changes
iter_changes(*, locale=None, since=None, until=None, after=None, on_progress=None) Lazy project-wide change iterator
change_pages(*, locale=None, start_page=1, cursor=None) Lazy validated pages with an opaque resume cursor
close() Closes an owned HTTP session

translations() and changes() require at least one positional key. translations() returns requested keys even when their result is empty. changes() returns a tuple and requests each selected key from the website. iter_changes() never accepts keys and remains lazy until iteration begins.

Invalid arguments raise ValueError. Network failures that remain after retries and responses that do not match the website contract raise RuntimeError.

Project and Locale

Project contains public project details and progress aggregated from the current locale states:

Field or property Description
slug Website project identifier
name Project name
description Project description, or None when absent
translation_context Translation guidance and terminology, or None when absent
key_count Current translation key count
locales Website-ordered tuple[Locale, ...]
language_count Configured locale count
translation_count Current translation count
missing_count Current missing translation count
review_count Current translations that need review
progress Integer completion percentage shown by the website

Each Locale contains code, translation_count, missing_count, review_count, and the derived progress. Locales without any current translations remain present in the project result.

Missing and Review

Both models contain key, locale, source, and translation_url. Review additionally contains previous_source, which is None when no previous source text exists. This source difference is distinct from changes to the translation itself.

Change

Each change has the following fields:

Field Description
id Website change identifier
key Translation key
locale Locale changed by the record
action added, modified, or deleted
old_value Previous text, or None for an addition
new_value New text, or None for a deletion
occurred_at UTC-aware datetime
translation_url Translation page for the key and locale
actor_login Contributor login, or None for an automated change
actor_url Contributor profile URL, when available
actor_avatar_url Contributor avatar URL, when available

ChangeAction is the literal type "added" | "modified" | "deleted". SOURCE_LOCALE is "en".

ChangePage

ChangePage contains number, total_pages, changes, and cursor. cursor corresponds to the final raw website record on the page, including a record that normalizes to no Change; callers should treat it only as an opaque resume value.

Performance reference

These reference measurements were taken from the public noctalia project in August 2026. They describe website requests without a local cache.

Operation Requests Reference result
project() One project page request Progress for 25 locales, about 23 KB
catalog() One complete export 42,857 strings, about 2.23 MB, 4.4–4.8 s
translations() One batch request per 50 keys Two keys and two locales, about 1.3 KB, about 1.4 s
search_translations() Search pages plus one batch request 19 Simplified Chinese matches, about 1.7 s
missing() One missing query plus batched source queries Matching entries and their English source text
reviews() One review query Matching keys and their English source difference
keys() One key-tree page About 2,474 keys and 147 KB
changes() One request per selected key Example key, about 1.3 KB and 1.4 s
iter_changes() Recent Changes pages until the boundary Depends on the requested range

Latency, server load, and project growth affect these values. Exact queries and text searches do not download the complete catalog.

Development

Install the locked development environment:

uv sync --locked

Run formatting, linting, type checking, and tests:

uv run ruff format --check .
uv run ruff check .
uv run basedpyright
uv run python -m unittest discover -v

The default suite validates models, response parsing, and client behavior without accessing external services.

Run the live contract tests explicitly to verify every public operation against the current public projects on Noctalia Translate:

uv run python -m unittest tests.live -v

Build and inspect both distributions:

uv build --no-sources --clear
uvx twine check --strict dist/*

License

MIT

Metadata

Release files for noctalia-i18n-core 0.3.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for noctalia-i18n-core 0.3.2
File Size Uploaded
noctalia_i18n_core-0.3.2.tar.gz 27.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for noctalia-i18n-core 0.3.2
File Interpreter ABI Platform
noctalia_i18n_core-0.3.2-py3-none-any.whl Python 3 none any Details

Total release size: 45.3 kB

Release files / noctalia_i18n_core-0.3.2.tar.gz

Download URL noctalia_i18n_core-0.3.2.tar.gz
Size 27.7 kB
Tags Source
SHA-256 checksum
How to use checksums
b3f18422265fe9f11df3d09fb8d8a86eb10d76536b0008cbe6cb3af8b15d12f1
BLAKE2b-256 checksum
How to use checksums
a9750cdda4772e142c7f86057d7b59e548b738b06f95e2af2ef2dabad7d12d2c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release files / noctalia_i18n_core-0.3.2-py3-none-any.whl

Download URL noctalia_i18n_core-0.3.2-py3-none-any.whl
Size 17.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
96a831d5adb6ec405818e78317bfbbdfe8d0e7be9943c1dc83e8fc0ef8e63531
BLAKE2b-256 checksum
How to use checksums
23e0c36e9a431e8e2362aee7f259216cdb4481088da561b2a75d62e5cfc87091
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.2 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page