dragoman

package module
v0.4.3 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2023 License: MIT Imports: 12 Imported by: 0

README

Dragoman - Translate structured documents

PkgGoDev Test

TL;DR – Translate JSON files, but preserve keys!

Translate the file i18n/en.json from English into German via DeepL while preserving placeholders and write the result to i18n/de.json:

translate json file i18n/en.json -o i18n/de.json --from en --into de --preserve '{[a-zA-Z]+?}' --deepl $DEEPL_AUTH_KEY
// i18n/en.json
{
  "title": "Hello, {firstName}! This is a title."
  "body": "And this is another sentence."
}

File gets translated, but property names and placeholder variables are preserved:

// i18n/de.json
{
  "title": "Hallo, {firstName}! Dies ist ein Titel."
  "body": "Und dies ist ein weiterer Satz."
}

Installation

CLI
go install github.com/bounoable/dragoman/cmd/translate@latest
API
go get github.com/bounoable/dragoman

CLI

Authentication

Choose and authenticate the underlying translation service by providing either one of these options:

  • --deepl $DEEPL_AUTH_KEY to use DeepL with your DeepL API key
  • --gcloud $CREDENTIALS_FILE to use Google Cloud Translation and authenticate with a credentials file

DeepL:

translate json text '{"foo": "Hello, my friend."}' --from en --into de --deepl $DEEPL_AUTH_KEY

# Output: {"foo": "Hallo, mein Freund."}

Google Cloud Translation:

translate json text '{"foo": "Hello, my friend."}' --from en --into de --gcloud ./credentials.json

# Output: {"foo": "Hallo, mein Freund."}
Translate files

The following example translates the JSON file en.json from English into German and writes the result to de.json:

translate json file en.json -o de.json --from en --into de --deepl $DEEPL_AUTH_KEY
Translate directories

The following example translates all JSON files in the directory i18n/en from English into German and writes the result to i18n/de:

translate json dir i18n/en -o i18n/de --from en --into de --deepl $DEEPL_AUTH_KEY
Preserve substrings (placeholders)
translate json text '{"foo": "Hello, {firstName}."}' --from en --into de --preserve '{[a-zA-Z]+?}' --deepl $DEEPL_AUTH_KEY

# Output: {"foo": "Hallo, {firstName}."}
Supported formats
  • json
  • html
Supported sources
  • text
  • file
  • dir
  • url

API

Authentication

Deepl:

import (
  "github.com/bounoable/dragoman"
  "github.com/bounoable/dragoman/service/deepl"
)

dm := dragoman.New(deepl.New(os.Getenv("DEEPL_AUTH_KEY")))

Google Cloud Translation:

import (
  "github.com/bounoable/dragoman"
  "github.com/bounoable/dragoman/service/gcloud"
)

svc, err := gcloud.NewFromCredentialsFile(context.TODO(), "./credentials.json")
// handle err
dm := dragoman.New(svc)
Translate files
import (
  "github.com/bounoable/dragoman"
  "github.com/bounoable/dragoman/format/json"
  "github.com/bounoable/dragoman/service/deepl"
)

func translateJSONFile(path, sourceLang, targetLang string) (string, error) {
  dm := dragoman.New(deepl.New(os.Getenv("DEEPL_AUTH_KEY")))

  f, err := os.Open()
  if err != nil {
    return fmt.Errorf("open file: %w", err)
  }
  defer f.Close()

  translated, err := dm.Translate(
    context.TODO(),
    f,
    sourceLang,
    targetLang,
    json.Ranger(),
    // options ...
  )
  if err != nil {
    return fmt.Errorf("translate file: %w", err)
  }

  return string(translated), nil
}

For more examples visit pkg.go.dev or example_test.go.

Preserve substrings (placeholders)

You can prevent translations of substrings matching a regular expression by using the Preserve() option:

// ...
res, _ := dm.Translate(
  context.Background(),
  strings.NewReader(`{"title": "Hello, {firstName}, how are you?"}`,
  "en", "de",
  dragoman.Preserve(regexp.MustCompile(`{[a-zA-Z]+?}`)),
))

fmt.Println(res)
// {"title": "Hallo, {firstName}, wie geht es Ihnen?"}

⚠ Note that matched substrings are cut out of the sentence, and the remaining parts are translated independently. The cut out parts are then reinserted between the translated strings, so if you have placeholders in sentences with complex grammar, the translated result may end up grammatically incorrect.

License

MIT

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Service

type Service interface {
	Translate(ctx context.Context, text, sourceLang, targetLang string) (string, error)
}

Service is a translation service (e.g. Google Translate / DeepL).

type TranslateOption

type TranslateOption func(*translateConfig)

A TranslateOption configures the translation behavior.

func Parallel

func Parallel(n int) TranslateOption

Parallel sets the maximum number of parallel translation requests.

func Preserve

func Preserve(expr *regexp.Regexp) TranslateOption

Preserve (prevent translation of) strings that match the given expr.

A typical use case are placeholder variables. Example:

  r, err := t.Translate(
    context.TODO(),
	   "Hello, {firstName}!",
	   "en", "de",
    dragoman.Preserve(regexp.MustCompile(`{[a-zA-Z0-9]+?}`)),
  )
  // r: "Hallo, {firstName}!"

type Translator

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

Translator is a structured-text translator.

func New

func New(service Service) *Translator

New returns a structured-text translator.

func (*Translator) Translate

func (t *Translator) Translate(
	ctx context.Context,
	input io.Reader,
	sourceLang, targetLang string,
	ranger text.Ranger,
	opts ...TranslateOption,
) ([]byte, error)

Translate the contents of input from sourceLang to targetLang.

Example (Html)
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/bounoable/dragoman"
	"github.com/bounoable/dragoman/format/html"
	"github.com/bounoable/dragoman/service/deepl"
)

func main() {
	svc := deepl.New(os.Getenv("DEEPL_AUTH_KEY"))
	dm := dragoman.New(svc)

	res, err := dm.Translate(
		context.TODO(),
		strings.NewReader(`<p>This is an example.</p>`),
		"en",
		"de",
		html.Ranger(),
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(res)
}
Output:

Example (HtmlWithAttributes)
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/bounoable/dragoman"
	"github.com/bounoable/dragoman/format/html"
	"github.com/bounoable/dragoman/service/deepl"
)

func main() {
	svc := deepl.New(os.Getenv("DEEPL_AUTH_KEY"))
	dm := dragoman.New(svc)

	res, err := dm.Translate(
		context.TODO(),
		strings.NewReader(`<p title="A title tag.">Hello, here is an <img src="someimage.jpeg" alt="An alternate description."></p>`),
		"en",
		"de",
		html.Ranger(
			html.WithAttribute("title", "alt"), // allow all `title` and `alt` attributes to be translated
			// OR
			html.MustAttributePath("p.title", "img.alt"), // allow `title` attribute of `p` tags and `alt` attribute of `img` tags to be translated
		),
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(res)
}
Output:

Example (HtmlWithPlaceholder)
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"regexp"
	"strings"

	"github.com/bounoable/dragoman"
	"github.com/bounoable/dragoman/format/html"
	"github.com/bounoable/dragoman/service/deepl"
)

func main() {
	svc := deepl.New(os.Getenv("DEEPL_AUTH_KEY"))
	dm := dragoman.New(svc)

	res, err := dm.Translate(
		context.TODO(),
		strings.NewReader(`<p>Hello, {firstName}, this is an example.</p>`),
		"en",
		"de",
		html.Ranger(),
		dragoman.Preserve(regexp.MustCompile(`{[a-zA-Z]+?}`)),
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(res)
}
Output:

Example (HtmlWithPlaceholderAndAttributes)
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"regexp"
	"strings"

	"github.com/bounoable/dragoman"
	"github.com/bounoable/dragoman/format/html"
	"github.com/bounoable/dragoman/service/deepl"
)

func main() {
	svc := deepl.New(os.Getenv("DEEPL_AUTH_KEY"))
	dm := dragoman.New(svc)

	res, err := dm.Translate(
		context.TODO(),
		strings.NewReader(`<p title="A title tag.">Hello, {firstName}, here is an <img src="someimage.jpeg" alt="An alternate description."></p>`),
		"en",
		"de",
		html.Ranger(
			html.MustAttributePath("p.title", "img.alt"), // allow `title` attribute of `p` tags and `alt` attribute of `img` tags to be translated
		),
		dragoman.Preserve(regexp.MustCompile(`{[a-zA-Z]+?}`)),
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(res)
}
Output:

Example (Json)
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/bounoable/dragoman"
	"github.com/bounoable/dragoman/format/json"
	"github.com/bounoable/dragoman/service/deepl"
)

func main() {
	svc := deepl.New(os.Getenv("DEEPL_AUTH_KEY"))
	dm := dragoman.New(svc)

	res, err := dm.Translate(
		context.TODO(),
		strings.NewReader(`{"title": "This is a title."}`),
		"en",
		"de",
		json.Ranger(),
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(string(res))
}
Output:

Example (JsonWithPlaceholder)
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"regexp"
	"strings"

	"github.com/bounoable/dragoman"
	"github.com/bounoable/dragoman/format/json"
	"github.com/bounoable/dragoman/service/deepl"
)

func main() {
	svc := deepl.New(os.Getenv("DEEPL_AUTH_KEY"))
	dm := dragoman.New(svc)

	res, err := dm.Translate(
		context.TODO(),
		strings.NewReader(`{"greeting": "Hello, {firstName}!"}`),
		"en",
		"de",
		json.Ranger(),
		dragoman.Preserve(regexp.MustCompile(`{[a-zA-Z]+?}`)),
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(res)
}
Output:

Directories

Path Synopsis
cmd
Package directory can be used to translate whole directories.
Package directory can be used to translate whole directories.
mocks
Package mock_directory is a generated GoMock package.
Package mock_directory is a generated GoMock package.
format
html
Package html provides translation of HTML files.
Package html provides translation of HTML files.
json
Package json provides translation of JSON files.
Package json provides translation of JSON files.
json/internal/lex
Package lex provides a very basic JSON lexer.
Package lex provides a very basic JSON lexer.
Package mock_dragoman is a generated GoMock package.
Package mock_dragoman is a generated GoMock package.
service
deepl
Package deepl provides the DeepL-backed translation service.
Package deepl provides the DeepL-backed translation service.
deepl/mocks
Package mock_deepl is a generated GoMock package.
Package mock_deepl is a generated GoMock package.
gcloud/mocks
Package mock_gcloud is a generated GoMock package.
Package mock_gcloud is a generated GoMock package.
mocks
Package mock_text is a generated GoMock package.
Package mock_text is a generated GoMock package.
preserve
Package preserve cuts substrings out of strings with the ability to reinsert them at a later time.
Package preserve cuts substrings out of strings with the ability to reinsert them at a later time.

Jump to

Keyboard shortcuts

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