gokagitranslate

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 11 Imported by: 0

README

go-kagi-translate

Unofficial Go client and CLI for translate.kagi.com.

This project uses Kagi Translate's private web API. It requires a valid Kagi subscription and can break when Kagi changes the web application or request contract.

A full example in the form of a cli can be found in cmd/ktranslate/main.go.

Features:

  • translate text programmatically via gokagitranslate.(*Kagi).Translate(ctx, from, to, text string)
  • detect the language of a text with gokagitranslate.(*Kagi).Detect(ctx, text string)
  • inspect quota usage programmatically via gokagitranslate.(*Kagi).Quota(ctx)
  • configurable API client via gokagitranslate.New(token, gokagitranslate.WithClient(...), gokagitranslate.WithUserAgent(...))
  • thread-safe auth session caching using an atomic cache with expiry-aware refreshes
  • uncomplicated opinionated oneshot translation via gokagitranslate.OneShot(ctx, token, from, to, text string)
  • netiquette adhering with both project name and contact email in user agent, dont @ me kagi team :)
  • cli tool for experimenting with all features the api provides (translation, quotas, language detection)

Install

go get github.com/xnacly/go-kagi-translate

For the CLI:

go install github.com/xnacly/go-kagi-translate/cmd/ktranslate@latest

Usage

package main

import (
	"context"
	"fmt"
	"os"

	gokagitranslate "github.com/xnacly/go-kagi-translate"
)

func main() {
	client := gokagitranslate.New(os.Getenv("KAGI_TOKEN"))

	translation, err := client.Translate(context.Background(), "es", "en", "me llamo teo")
	if err != nil {
		panic(err)
	}
	fmt.Println(translation.Translation)

	detected, err := client.Detect(context.Background(), "agur, zer moduz zaude?")
	if err != nil {
		panic(err)
	}
	fmt.Println(detected.DetectedLanguage.Iso)

	quota, err := client.Quota(context.Background())
	if err != nil {
		panic(err)
	}
	fmt.Println(quota.Translate.Remaining)
}

For lower-level translation options, use TranslateWithParams:

res, err := client.TranslateWithParams(context.Background(), gokagitranslate.TranslateParams{
	Text:               "hello",
	From:               "en",
	To:                 "es",
	Formality:          "default",
	SpeakerGender:      "unknown",
	AddresseeGender:    "unknown",
	LanguageComplexity: "standard",
	TranslationStyle:   "natural",
	Model:              "standard",
})

Language detection is best-effort, especially for short or ambiguous text. To provide Kagi with UI-like recent language context, use DetectWithParams:

res, err := client.DetectWithParams(context.Background(), gokagitranslate.DetectParams{
	Text:                "agur",
	IncludeAlternatives: true,
	RecentLanguages:     []string{"eu", "es", "en"},
})

CLI

The CLI expects KAGI_TOKEN in the environment:

KAGI_TOKEN=... ktranslate translate -from es -to en "me llamo matteo"
KAGI_TOKEN=... ktranslate detect -json "agur, zer moduz zaude?"
KAGI_TOKEN=... ktranslate detect -json -recent eu,es,en "agur"
KAGI_TOKEN=... ktranslate quota

Reason

I use kagi translate daily in a large fashion due to working with spanish, american, russian and german colleagues. Since I currently live in the basque country and kagi has high quality spanish and basque source and target translations I wanted to use said product programmatically via a rest api, only to discover: There is no documentation and the seemingly available beta program is gated behind writing the support with my usecase and then I would, somehow get an api key. Anyway, this is the reversed web api, if you have a subscription, thus a session link and token, have fun.

Authentication

This requires a subscription to kagi, since translate is only available to this.

Both the example mentioned before and the tests expect the kagi private session token in the KAGI_TOKEN env variable, this value can be get from the starred (*) section of the session link one can request from kagi when going to the sidebar on kagi.com and clicking on Copy in the Session Link section:

https://kagi.com/search?token=***************************************************************************************&q=%s

Documentation

Index

Constants

View Source
const (

	// DefaultUserAgent identifies this unofficial client to Kagi.
	DefaultUserAgent = "" /* 153-byte string literal not displayed */
)

Variables

View Source
var ErrEmptyResponse = errors.New("empty response")

Functions

func OneShot

func OneShot(ctx context.Context, token, from, to, text string) (string, error)

OneShot translates text directly using token for authentication.

Types

type AuthResponse

type AuthResponse struct {
	Token              string    `json:"token"`
	ID                 string    `json:"id"`
	LoggedIn           bool      `json:"loggedIn"`
	Subscription       bool      `json:"subscription"`
	ExpiresAt          time.Time `json:"expiresAt"`
	Theme              string    `json:"theme"`
	MobileTheme        string    `json:"mobileTheme"`
	CustomCSSEnabled   bool      `json:"customCssEnabled"`
	Language           string    `json:"language"`
	CustomCSSAvailable bool      `json:"customCssAvailable"`
	AccountType        string    `json:"accountType"`
	Platform           string    `json:"platform"`
}

AuthResponse is returned by Kagi's auth endpoint.

type DetectParams

type DetectParams struct {
	Text                string   `json:"text"`
	IncludeAlternatives bool     `json:"include_alternatives"`
	RecentLanguages     []string `json:"recent_languages,omitempty"`
	SessionToken        string   `json:"session_token,omitempty"`
}

DetectParams contains the request body sent to Kagi's detect endpoint.

type DetectResponse

type DetectResponse struct {
	DetectedLanguage Language   `json:"detected_language"`
	Alternatives     []Language `json:"alternatives,omitempty"`
}

DetectResponse is returned by Kagi's detect endpoint.

type Kagi

type Kagi struct {
	// contains filtered or unexported fields
}

Kagi is a client for Kagi Translate's private web API.

func New

func New(token string, options ...Option) *Kagi

New creates a Kagi client authenticated with a Kagi session token.

func (*Kagi) Detect

func (kt *Kagi) Detect(ctx context.Context, text string) (DetectResponse, error)

Detect detects the language of text using standard options.

func (*Kagi) DetectWithParams

func (kt *Kagi) DetectWithParams(ctx context.Context, params DetectParams) (DetectResponse, error)

DetectWithParams detects the language of text using the provided options.

func (*Kagi) Quota

func (kt *Kagi) Quota(ctx context.Context) (QuotaResponse, error)

Quota returns the authenticated account's Kagi Translate quota usage.

func (*Kagi) Translate

func (kt *Kagi) Translate(ctx context.Context, from, to, text string) (TranslateResponse, error)

Translate translates text from one language to another using standard options.

func (*Kagi) TranslateWithParams

func (kt *Kagi) TranslateWithParams(ctx context.Context, params TranslateParams) (TranslateResponse, error)

TranslateWithParams translates text using the provided low-level options.

type Language

type Language struct {
	Iso   string `json:"iso"`
	Label string `json:"label"`
}

Language identifies a detected or translated language.

type Option added in v1.1.0

type Option func(*Kagi)

Option configures a Kagi client at construction time.

func WithClient added in v1.1.0

func WithClient(client *http.Client) Option

WithClient configures the HTTP client used for requests.

func WithUserAgent added in v1.1.0

func WithUserAgent(userAgent string) Option

WithUserAgent configures the User-Agent header used for requests.

type Quota

type Quota struct {
	Kind        string    `json:"kind"`
	Used        int       `json:"used"`
	Limit       int       `json:"limit"`
	Remaining   int       `json:"remaining"`
	Percent     float64   `json:"percent"`
	Exceeded    bool      `json:"exceeded"`
	ResetsAt    time.Time `json:"resetsAt"`
	Exempt      bool      `json:"exempt"`
	ActiveJobID *string   `json:"activeJobId,omitempty"`
}

Quota describes usage for one Kagi Translate quota bucket.

type QuotaResponse

type QuotaResponse struct {
	Translate Quota `json:"translate"`
	Proofread Quota `json:"proofread"`
	Document  Quota `json:"document"`
}

QuotaResponse is returned by Kagi's quota endpoint.

type TranslateParams

type TranslateParams struct {
	Text                   string `json:"text"`
	From                   string `json:"from"`
	To                     string `json:"to"`
	Stream                 bool   `json:"stream"`
	PredictedLanguage      string `json:"predicted_language,omitempty"`
	Formality              string `json:"formality"`
	SpeakerGender          string `json:"speaker_gender"`
	AddresseeGender        string `json:"addressee_gender"`
	LanguageComplexity     string `json:"language_complexity"`
	TranslationStyle       string `json:"translation_style"`
	Context                string `json:"context"`
	Model                  string `json:"model"`
	SessionToken           string `json:"session_token"`
	DictionaryLanguage     string `json:"dictionary_language"`
	UseDefinitionContext   bool   `json:"use_definition_context"`
	EnableLanguageFeatures bool   `json:"enable_language_features"`
}

TranslateParams contains the request body sent to Kagi's translate endpoint.

type TranslateResponse

type TranslateResponse struct {
	Translation      string   `json:"translation"`
	DetectedLanguage Language `json:"detected_language"`
	Definition       struct {
		Word           string `json:"word"`
		PrimaryMeaning struct {
			Definition            string   `json:"definition"`
			PartOfSpeech          []string `json:"part_of_speech"`
			PartOfSpeechCanonical []string `json:"part_of_speech_canonical"`
			UsageLevel            []string `json:"usage_level"`
			Synonyms              []string `json:"synonyms"`
			SynonymComparisons    []struct {
				Synonym    string `json:"synonym"`
				Difference string `json:"difference"`
			} `json:"synonym_comparisons,omitempty"`
		} `json:"primary_meaning"`
		SecondaryMeanings []struct {
			Definition            string   `json:"definition"`
			PartOfSpeech          []string `json:"part_of_speech"`
			PartOfSpeechCanonical []string `json:"part_of_speech_canonical"`
			UsageLevel            []string `json:"usage_level"`
			Synonyms              []string `json:"synonyms"`
			SynonymComparisons    []struct {
				Synonym    string `json:"synonym"`
				Difference string `json:"difference"`
			} `json:"synonym_comparisons,omitempty"`
		} `json:"secondary_meanings"`
		Examples      []string `json:"examples"`
		Pronunciation string   `json:"pronunciation"`
		Etymology     string   `json:"etymology"`
		Notes         string   `json:"notes"`
		TemporalTrend string   `json:"temporal_trend"`
		RelatedWords  []struct {
			Word         string `json:"word"`
			Relationship string `json:"relationship"`
		} `json:"related_words"`
	} `json:"definition"`
}

TranslateResponse is returned by Kagi's translate endpoint.

Directories

Path Synopsis
cmd
ktranslate command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL