Pređi na sadržaj

SDK i klijenti

Ovde se dve različite stvari zovu SDK i rešavaju različite probleme.

  • Klijenti za izvršavanje preuzimaju prevode iz OTA paketa i razrešavaju ključeve u vašoj aplikaciji. Postoje za Go, Rust i NestJS.
  • Pregledački SDK ne preuzima ništa: on označava DOM elemente ključem iz kog su nastali, da bi Chrome ekstenzija mogla da prikaže i izmeni prevod preko vašeg proizvoda dok radi.

Klijenti za izvršavanje

heading.anchorLabel

Sva tri rade isto: uperite ih na izvor, oni ga učitaju u memoriju, osvežavaju u pozadini na svakih pet minuta i razrešavaju ključ po imenskom prostoru i lokalu.

Dostupna su dva izvora:

  • OTA — jedan ili više objavljenih paketa, adresiranih pristupnim ključem. Svakom paketu se može dati prefiks, koji postaje njegov imenski prostor; više paketa sa istim prefiksom se spaja, a pri sudaru ključeva poslednji pobeđuje.
  • Map — mapa prevoda projekta, adresirana identifikatorom projekta i API ključem. Tu ime fajla postaje imenski prostor.
Terminal window
go get github.com/OwnLate/go-client
client, err := ownlate.New(ownlate.Config{
Source: ownlate.OTASource{Bundles: []ownlate.OTABundle{{AccessKey: accessKey}}},
Locale: "sr",
})
if err != nil {
return err
}
defer client.Close()
client.Start(ctx)
<-client.Ready()
client.T("notification.title", "en_US")
client.Translate("emails", "greeting", map[string]any{"name": "Roman"}, "sr")

Start osvežava u pozadini i ponavlja pokušaje pri neuspehu; Load radi jedno učitavanje i vraća grešku.

[dependencies]
ownlate = { git = "https://github.com/OwnLate/rust-client" }
let client = ownlate::Client::ota(access_key, "en_US")?;
let refresh = client.start();
client.ready().await;
client.t("notification.title", "en_US");
client.translate("emails", "subject", Some(&json!({ "plan": "Pro" })), "en_US");

Client se jeftino klonira — svi klonovi dele iste prevode i isti zadatak osvežavanja. Ako se vraćeni handle odbaci, osvežavanje prestaje.

Terminal window
npm install @globalart/ownlate-nestjs-translator

Modul obavija isto ponašanje za Nest aplikaciju: učitava paket pri pokretanju i osvežava ga u pozadini.

Kako se ključ razrešava

heading.anchorLabel

Klijenti se slažu oko pravila, i zato je nedostajući prevod bezopasan:

  1. Lokal dolazi iz poziva, inače iz konfiguracije klijenta.
  2. Traži se imenski prostor; za OTA izvor nepoznat prostor svodi se na podrazumevani paket.
  3. Nedostajući lokal zamenjuje se lokalom istog jezika — en_US doseže en i obrnuto — a ako ni to ne uspe, prvim po abecedi, pa izbor ostaje stabilan između poziva.
  4. Nepoznat ključ vraća se onakav kakav je zatražen, nikad kao prazan tekst.
  5. Zamene oblika {{name}} popunjavaju se prosleđenim vrednostima.

Oba klijenta čitaju snimak pod bravom i pri osvežavanju menjaju ceo snimak, pa ih je bezbedno deliti između gorutina i zadataka.

Pregledački SDK

heading.anchorLabel

@ownlate/sdk označava DOM. On je ono što vašu aplikaciju u radu pretvara u nešto što prevodilac može da menja na licu mesta.

Terminal window
npm install @ownlate/sdk
import { init, wrapT } from '@ownlate/sdk'
init({
projectId: 'your-project-id',
workspaceId: 'your-workspace-id',
apiKey: 'sdk_…',
apiUrl: 'https://api.ownlate.com',
})

Obavijte svoju i18n funkciju jednom i svaki tekst koji ona iscrta biva označen:

import { useTranslation } from 'react-i18next'
import { wrapT } from '@ownlate/sdk'
function Title() {
const { t: rawT } = useTranslation()
const t = wrapT(rawT)
return <h1>{t('home.title')}</h1>
}
IzvozPotpisŠta radi
init(config) => voidPokreće SDK. Poziva se jednom.
wrapT(t) => tObavija i18n t() tako da se iscrtani čvorovi označavaju
annotateElement(el, key) => voidRučno označava čvor
onTranslationUpdate(cb) => unsubscribeReaguje na izmenu napravljenu u ekstenziji
destroy() => voidUklanja slušaoce i vraća početno stanje

annotateElement koristite tamo gde wrapT ne vidi čvor — placeholder, aria-label, atribut title:

annotateElement(document.querySelector('#search'), 'search.placeholder')

I primenjujte izmene uživo, bez osvežavanja:

onTranslationUpdate(({ key, value, lang }) => {
i18next.addResource(lang, 'translation', key, value)
})

Kako se sve uklapa

heading.anchorLabel
  1. init() se javlja preko postMessage, što hvata content script ekstenzije.
  2. wrapT() i annotateElement() postavljaju čvorovima atribut data-ownlate-key.
  3. Ekstenzija čita te atribute i prikazuje odgovarajuće segmente u bočnom panelu.
  4. Izmena u panelu čuva se kao nacrt na segmentu i šalje nazad na stranicu, pa se interfejs odmah ažurira.

Pošto izmene padaju kao nacrti, uređivanje na licu mesta nikad ne zaobilazi recenziju.

Pregledački SDK se autentifikuje SDK tokenom, ne API ključem. Tokeni se prave po projektu na kartici SDK, i svaki:

  • prikazuje se jednom, pri kreiranju, a posle samo prefiksom;
  • doseže tačno jedan projekat — onaj za koji je napravljen;
  • ume da čita segmente po ključu i čuva nacrte prevoda, i ništa više;
  • beleži kada je poslednji put korišćen i može se opozvati bilo kada.

Ta uskost je poenta: token putuje u pregledačkom paketu, pa ne sme da može ništa što vam ne bi bilo svejedno da uradi neko sa strane.