Vývoj doplnkov

Doplnky sú spôsobom prispôsobenia pracovného postupu lokalizácie vo Weblate.

class weblate.addons.base.BaseAddon(storage)

Base class for Weblate add-ons.

classmethod can_install(*, component=None, category=None, project=None) → bool

Check whether add-on is compatible with given component.

change_event(change, activity_log_id: int | None = None)

Event handler for change event.

check_change_action(change) → bool

Early filtering of Change actions before triggering change_event callback.

component_update(component, activity_log_id: int | None = None)

Event handler for component update.

configure(configuration) → None

Save configuration.

daily(component=None, category=None, project=None, activity_log_id: int | None = None)

Scope-aware daily entry point.

Override this for project-level logic, or override daily_component() for per-component logic.

daily_component(component, activity_log_id: int | None = None)

Per-component daily processing. Override this for component-level logic.

classmethod get_add_form(user, *, component=None, category=None, project=None, **kwargs)

Return configuration form for adding new add-on.

classmethod get_api_urls()

Return named Django URL patterns for this provider’s API.

get_change_details(compared_configuration)

Return a public configuration snapshot and changed field names.

get_execution_form(data: Mapping[str, object] | None = None) → Form | None

Provide optional component/change context and preview controls.

get_public_configuration()

Return configuration with non-public values redacted.

classmethod get_public_configuration_fields() → frozenset[str]

Return configuration fields which are safe for public use.

get_settings_form(user, **kwargs)

Return configuration form for this add-on.

manual(component=None, category=None, project=None, activity_log_id: int | None = None)

Scope-aware manual entry point.

By default this mirrors the daily handler and lets add-ons opt in explicitly by subscribing to the manual event.

manual_component(component, activity_log_id: int | None = None)

Per-component manual processing.

post_add(translation, activity_log_id: int | None = None)

Event handler after new translation is added.

post_commit(component, store_hash: bool, activity_log_id: int | None = None)

Event handler after changes are committed to the repository.

post_install(component, store_hash: bool, activity_log_id: int | None = None)

Event handler after add-on is installed.

post_push(component, activity_log_id: int | None = None)

Event handler after repository is pushed upstream.

post_remove(translation, activity_log_id: int | None = None)

Event handler after a translation is removed.

post_update(component, previous_head: str, skip_push: bool, changed_files: list[str], parse_after_update: bool = False, activity_log_id: int | None = None)

Event handler after repository is updated from upstream.

Parametre:
  • previous_head (str) – HEAD of the repository prior to update, can be blank on initial clone.

  • skip_push (bool) – Whether the add-on operation should skip pushing changes upstream. Usually you can pass this to underlying methods as commit_and_push or commit_pending.

  • changed_files (list[str]) – Files changed by the repository update.

pre_commit(translation, author: str, store_hash: bool, activity_log_id: int | None = None)

Event handler before changes are committed to the repository.

pre_push(component, activity_log_id: int | None = None)

Event handler before repository is pushed upstream.

pre_update(component, activity_log_id: int | None = None)

Event handler before repository is updated from upstream.

preview(workflow: object, component_id: int | None, change_id: int | None = None, actor=None) → dict[str, object]

Preview an operation without changing application state, if supported.

resolve_components(*, component=None, category=None, project=None)

Resolve scope to components iterator.

save_state() → None

Save add-on state information.

schedule_manual_run(user_id: int | None = None, *, component_id: int | None = None, change_id: int | None = None) → None

Queue the default manual handler; providers can consume run context.

unit_pre_create(unit, activity_log_id: int | None = None)

Event handler before new unit is created.

update_component_state(component, updater: Callable[[dict[str, object]], None]) → None

Atomically merge component-scoped add-on state into the shared JSON field.

user()

Weblate user used to track changes by this add-on.

Háčiky doplnkov prijímajú objekty ORM z modulov weblate.*.models, vrátane Addon, Component, Translation, Category, Project, Unit, Change a User. Formuláre konfigurácie doplnkov by mali dediť od weblate.addons.forms.BaseAddonForm.

Tu je príklad doplnku:

# Copyright © Michal Čihař <michal@weblate.org>
#
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import annotations

from typing import TYPE_CHECKING, ClassVar

from django.utils.translation import gettext_lazy

from weblate.addons.base import BaseAddon
from weblate.addons.events import AddonEvent

if TYPE_CHECKING:
    from weblate.addons.base import CompatDict
    from weblate.trans.models import Translation


class ExampleAddon(BaseAddon):
    # Filter for compatible components, every key is
    # matched against property of component
    compat: ClassVar[CompatDict] = {
        "file_format": {"po", "po-mono"},
    }
    # List of events add-on should receive
    events: ClassVar[set[AddonEvent]] = {
        AddonEvent.EVENT_PRE_COMMIT,
    }
    # Add-on unique identifier
    name = "weblate.example.example"
    # Verbose name shown in the user interface
    verbose = gettext_lazy("Example add-on")
    # Detailed add-on description
    description = gettext_lazy("This add-on does nothing it is just an example.")

    # Callback to implement custom behavior
    def pre_commit(
        self,
        translation: Translation | None,
        author: str,
        store_hash: bool,
        activity_log_id: int | None = None,
    ) -> None:
        return

Dokumentovanie operácií automatizácie

Referencia automatizácie a kuchárska kniha používa schému v weblate/automation/schema.py ako svoj referenčný zdroj. Vstavané akcie sú registrované v weblate/automation/operations.py, ktorý poskytuje ich nastavenia a schémy výsledkov, validáciu a vykonávanie. Tento register uchovávajte interne; nenačítava operácie tretích strán. Pri pridávaní akcie nastavte jej názov a verziu pridanú do vydania Weblate, v ktorom sa prvýkrát objaví. Túto verziu zachovajte aj pri neskoršom rozširovaní akcie. Riadiace bloky si v schéme pracovného postupu uchovávajú svoje metadáta title a x-version-added.

V položke registra deklarujte podporované rozsahy reťazcov akcie. Predvolená hodnota je component; zvoľte trigger a result, keď vykonávanie akceptuje výber jednotky za behu. Rozsah odovzdajte normalizácii, aby predvolené hodnoty a požiadavky dotazu zodpovedali výberu. Nahláste ovplyvnené ID jednotiek prostredníctvom zberača za behu, nie cez verejnú schému výsledkov alebo protokol aktivít.

Spustite make -C docs update-automation-schema update-automation-docs na aktualizáciu schémy a referencie na stiahnutie. Pridajte vysvetlenia a príklady po zodpovedajúci marker AUTOGENERATED END v docs/admin/automation.rst. Generátor list_automation zachováva tento manuálny obsah. Udržiavajte identifikátory sekcií stabilné, aby popisy zostali priradené k svojim operáciám.

Typovanie konfigurácie doplnku

Konfigurácia doplnku je uložená v poli JSON Addon.configuration, takže model uchováva persistované dáta ako surové JSON. Implementácie doplnkov môžu typovať svoju vlastnú konfiguráciu parametrizáciou BaseAddon a BaseAddonForm.

Použite dve triedy TypedDict, keď sa uložené JSON môže líšiť od runtime tvaru: permisivnú, zvyčajne total=False, uloženú konfiguráciu pre staré alebo chýbajúce hodnoty a úplnú runtime konfiguráciu vrátenú normalize_configuration(). Runtime kód doplnku by mal čítať self.configuration alebo self.get_configuration(), aby videl normalizované predvolené hodnoty namiesto surového persistovaného JSON.

Pre jednoduché doplnky, kde sú uložený a runtime tvar identické, definujte jediný TypedDict a použite ho pre oba typové parametre BaseAddon. Udržujte návratový typ serialize_form() formulára v súlade s typom uloženej konfigurácie.

Zverejnenie konfigurácie doplnku

Add-on change history can be visible without add-on management permission. List configuration fields that are safe to publish in the form’s public_configuration_fields attribute. Fields not explicitly listed are kept in the snapshot with a null value and identified as redacted. The default is an empty set so that newly added settings are not published accidentally. Allowlisting a structured field publishes all its nested values. Only list such a field when every value it can contain is safe to publish.

Použite BaseAddon.get_public_configuration() vždy, keď je konfigurácia vystavená mimo dôveryhodného kódu na správu doplnkov. Interné operácie, ktoré zámerne klonujú funkčný doplnok, môžu naďalej používať uloženú konfiguráciu.

API doplnkov pripojených ku komponentu

Deklarujte api_name a vráťte pomenované vzory URL Django z get_api_urls(). Používajte bežné konvertory Django a pohľady DRF. Vzory sú registrované pre každého poskytovateľa povoleného v WEBLATE_ADDONS, bez ohľadu na to, či je doplnok nainštalovaný na komponente.

Trasy sú namontované pod /api/components/<projekt>/<komponent>/addons/<api_name>/. Pre kategorizované komponenty zakódujte celú cestu kategórie a komponentu v segmente komponentu, ako pre REST API komponentu. Použite api_url inštalácie namiesto manuálneho zostavovania tejto URL. Názvy API musia obsahovať 1 až 64 znakov ASCII písmen, číslic, podčiarkovníkov alebo pomlčiek a musia byť globálne jedinečné medzi povolenými triedami poskytovateľov. Weblate validuje tieto deklarácie pri spustení bez dopytovania databázy a odmieta neplatné alebo konfliktné názvy. Poskytovatelia musia deklarovať needs_component = True, repo_scope = False a multiple = False. Ten istý poskytovateľ môže byť nainštalovaný na mnohých komponentoch, ale na každom komponente iba raz.

Vytvorte podtriedu weblate.addons.api.InstalledAddonAPIView a nastavte jej addon_name na interný názov doplnku poskytovateľa. Základný pohľad autentifikuje požiadavku, kontroluje prístup ku komponentu a rieši inštaláciu ako self.addon. Chýbajúca alebo nekompatibilná inštalácia vracia HTTP 404. Jeho permission má predvolenú hodnotu component.edit a kontroluje sa pred analýzou údajov požiadavky. Predvolený analyzátor JSON obmedzuje požiadavky na 5 MiB, vrátane požiadaviek bez hlavičky Content-Length.

Používajte bežnú validáciu serializátora DRF v metódach pohľadu. Zdokumentujte celú zmluvu pomocou drf_spectacular.utils.extend_schema a pomocného textu polí serializátora: OpenAPI objavuje rovnaké pohľady používané na smerovanie za behu. Obráťte koncové body pomocou api:<api_name>:<pattern_name> a poskytnite project__slug, slug a všetky parametre koncového bodu. Názvy API sú verejné zmluvy a mali by zostať stabilné naprieč zmenami implementácie. Po zmene registrácie poskytovateľa reštartujte Weblate; testy prepisujúce registrácie musia znovu zostaviť svoju konfiguráciu URL a vyčistiť cache URL Django.

Existujúce manažérske API /api/addons/<id>/ zostáva dostupné. Jeho polia iba na čítanie api_name a api_url odrážajú aktuálnu deklaráciu povoleného poskytovateľa. Obe sú nulové, keď je poskytovateľ zakázaný alebo nekompatibilný.

Testovanie zdrojov Kotlin SDK

Spustite uv run pytest weblate/kotlin_sdk/tests.py s nakonfigurovaným testovacím prostredím na testovanie extrakcie, prípravy a publikovania zdrojov, vrátane API Kotlin SDK.

Testy binárneho zapisovača, validácia AAPT2 a inštrumentačné testy Androidu sa udržiavajú v arsc-writer. Inštrukcie nájdete v jeho vývojovej príručke.