1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-08-26 18:21:01 +00:00

feat(integration): add LinkTaco service for saving articles

This commit is contained in:
Peter Sanchez 2025-08-20 21:35:33 -06:00 committed by GitHub
parent 983291c78b
commit 4d656d2739
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 939 additions and 5 deletions

View file

@ -72,7 +72,7 @@ Features
### Integrations ### Integrations
- 25+ integrations with third-party services: [Apprise](https://github.com/caronc/apprise), [Betula](https://sr.ht/~bouncepaw/betula/), [Cubox](https://cubox.cc/), [Discord](https://discord.com/), [Espial](https://github.com/jonschoning/espial), [Instapaper](https://www.instapaper.com/), [LinkAce](https://www.linkace.org/), [Linkding](https://github.com/sissbruecker/linkding), [LinkWarden](https://linkwarden.app/), [Matrix](https://matrix.org), [Notion](https://www.notion.com/), [Ntfy](https://ntfy.sh/), [Nunux Keeper](https://keeper.nunux.org/), [Pinboard](https://pinboard.in/), [Pushover](https://pushover.net), [RainDrop](https://raindrop.io/), [Readeck](https://readeck.org/en/), [Readwise Reader](https://readwise.io/read), [RssBridge](https://rss-bridge.org/), [Shaarli](https://github.com/shaarli/Shaarli), [Shiori](https://github.com/go-shiori/shiori), [Slack](https://slack.com/), [Telegram](https://telegram.org), [Wallabag](https://www.wallabag.org/), etc. - 25+ integrations with third-party services: [Apprise](https://github.com/caronc/apprise), [Betula](https://sr.ht/~bouncepaw/betula/), [Cubox](https://cubox.cc/), [Discord](https://discord.com/), [Espial](https://github.com/jonschoning/espial), [Instapaper](https://www.instapaper.com/), [LinkAce](https://www.linkace.org/), [Linkding](https://github.com/sissbruecker/linkding), [LinkTaco](https://linktaco.com), [LinkWarden](https://linkwarden.app/), [Matrix](https://matrix.org), [Notion](https://www.notion.com/), [Ntfy](https://ntfy.sh/), [Nunux Keeper](https://keeper.nunux.org/), [Pinboard](https://pinboard.in/), [Pushover](https://pushover.net), [RainDrop](https://raindrop.io/), [Readeck](https://readeck.org/en/), [Readwise Reader](https://readwise.io/read), [RssBridge](https://rss-bridge.org/), [Shaarli](https://github.com/shaarli/Shaarli), [Shiori](https://github.com/go-shiori/shiori), [Slack](https://slack.com/), [Telegram](https://telegram.org), [Wallabag](https://www.wallabag.org/), etc.
- Bookmarklet for subscribing to websites directly from any web browser. - Bookmarklet for subscribing to websites directly from any web browser.
- Webhooks for real-time notifications or custom integrations. - Webhooks for real-time notifications or custom integrations.
- Compatibility with existing mobile applications using the Fever or Google Reader API. - Compatibility with existing mobile applications using the Fever or Google Reader API.

View file

@ -1135,4 +1135,20 @@ var migrations = []func(tx *sql.Tx) error{
_, err = tx.Exec(sql) _, err = tx.Exec(sql)
return err return err
}, },
func(tx *sql.Tx) (err error) {
sql := `
CREATE TYPE linktaco_link_visibility AS ENUM (
'PUBLIC',
'PRIVATE'
);
ALTER TABLE integrations
ADD COLUMN linktaco_enabled bool default 'f',
ADD COLUMN linktaco_api_token text default '',
ADD COLUMN linktaco_org_slug text default '',
ADD COLUMN linktaco_tags text default '',
ADD COLUMN linktaco_visibility linktaco_link_visibility default 'PUBLIC';
`
_, err = tx.Exec(sql)
return err
},
} }

View file

@ -15,6 +15,7 @@ import (
"miniflux.app/v2/internal/integration/karakeep" "miniflux.app/v2/internal/integration/karakeep"
"miniflux.app/v2/internal/integration/linkace" "miniflux.app/v2/internal/integration/linkace"
"miniflux.app/v2/internal/integration/linkding" "miniflux.app/v2/internal/integration/linkding"
"miniflux.app/v2/internal/integration/linktaco"
"miniflux.app/v2/internal/integration/linkwarden" "miniflux.app/v2/internal/integration/linkwarden"
"miniflux.app/v2/internal/integration/matrixbot" "miniflux.app/v2/internal/integration/matrixbot"
"miniflux.app/v2/internal/integration/notion" "miniflux.app/v2/internal/integration/notion"
@ -242,6 +243,29 @@ func SendEntry(entry *model.Entry, userIntegrations *model.Integration) {
} }
} }
if userIntegrations.LinktacoEnabled {
slog.Debug("Sending entry to LinkTaco",
slog.Int64("user_id", userIntegrations.UserID),
slog.Int64("entry_id", entry.ID),
slog.String("entry_url", entry.URL),
)
client := linktaco.NewClient(
userIntegrations.LinktacoAPIToken,
userIntegrations.LinktacoOrgSlug,
userIntegrations.LinktacoTags,
userIntegrations.LinktacoVisibility,
)
if err := client.CreateBookmark(entry.URL, entry.Title, entry.Content); err != nil {
slog.Error("Unable to send entry to LinkTaco",
slog.Int64("user_id", userIntegrations.UserID),
slog.Int64("entry_id", entry.ID),
slog.String("entry_url", entry.URL),
slog.Any("error", err),
)
}
}
if userIntegrations.LinkwardenEnabled { if userIntegrations.LinkwardenEnabled {
slog.Debug("Sending entry to linkwarden", slog.Debug("Sending entry to linkwarden",
slog.Int64("user_id", userIntegrations.UserID), slog.Int64("user_id", userIntegrations.UserID),

View file

@ -0,0 +1,146 @@
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package linktaco // import "miniflux.app/v2/internal/integration/linktaco"
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"miniflux.app/v2/internal/version"
)
const (
defaultClientTimeout = 10 * time.Second
defaultGraphQLURL = "https://api.linktaco.com/query"
maxTags = 10
maxDescriptionLength = 500
)
type Client struct {
graphqlURL string
apiToken string
orgSlug string
tags string
visibility string
}
func NewClient(apiToken, orgSlug, tags, visibility string) *Client {
if visibility == "" {
visibility = "PUBLIC"
}
return &Client{
graphqlURL: defaultGraphQLURL,
apiToken: apiToken,
orgSlug: orgSlug,
tags: tags,
visibility: visibility,
}
}
func (c *Client) CreateBookmark(entryURL, entryTitle, entryContent string) error {
if c.apiToken == "" || c.orgSlug == "" {
return fmt.Errorf("linktaco: missing API token or organization slug")
}
description := entryContent
if len(description) > maxDescriptionLength {
description = description[:maxDescriptionLength]
}
// tags (limit to 10)
tags := strings.FieldsFunc(c.tags, func(c rune) bool {
return c == ',' || c == ' '
})
if len(tags) > maxTags {
tags = tags[:maxTags]
}
// tagsStr is used in GraphQL query to pass comma separated tags
tagsStr := strings.Join(tags, ",")
mutation := `
mutation AddLink($input: LinkInput!) {
addLink(input: $input) {
id
url
title
}
}
`
variables := map[string]any{
"input": map[string]any{
"url": entryURL,
"title": entryTitle,
"description": description,
"orgSlug": c.orgSlug,
"visibility": c.visibility,
"unread": true,
"starred": false,
"archive": false,
"tags": tagsStr,
},
}
requestBody, err := json.Marshal(map[string]any{
"query": mutation,
"variables": variables,
})
if err != nil {
return fmt.Errorf("linktaco: unable to encode request body: %v", err)
}
request, err := http.NewRequest(http.MethodPost, c.graphqlURL, bytes.NewReader(requestBody))
if err != nil {
return fmt.Errorf("linktaco: unable to create request: %v", err)
}
request.Header.Set("Content-Type", "application/json")
request.Header.Set("User-Agent", "Miniflux/"+version.Version)
request.Header.Set("Authorization", "Bearer "+c.apiToken)
httpClient := &http.Client{Timeout: defaultClientTimeout}
response, err := httpClient.Do(request)
if err != nil {
return fmt.Errorf("linktaco: unable to send request: %v", err)
}
defer response.Body.Close()
if response.StatusCode >= 400 {
return fmt.Errorf("linktaco: unable to create bookmark: status=%d", response.StatusCode)
}
var graphqlResponse struct {
Data json.RawMessage `json:"data"`
Errors []json.RawMessage `json:"errors"`
}
if err := json.NewDecoder(response.Body).Decode(&graphqlResponse); err != nil {
return fmt.Errorf("linktaco: unable to decode response: %v", err)
}
if len(graphqlResponse.Errors) > 0 {
// Try to extract error message
var errorMsg string
for _, errJSON := range graphqlResponse.Errors {
var errObj struct {
Message string `json:"message"`
}
if json.Unmarshal(errJSON, &errObj) == nil && errObj.Message != "" {
errorMsg = errObj.Message
break
}
}
if errorMsg == "" {
// Fallback. Should never be reached.
errorMsg = "GraphQL error occurred (fallback message)"
}
return fmt.Errorf("linktaco: %s", errorMsg)
}
return nil
}

View file

@ -0,0 +1,440 @@
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package linktaco
import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestCreateBookmark(t *testing.T) {
tests := []struct {
name string
apiToken string
orgSlug string
tags string
visibility string
entryURL string
entryTitle string
entryContent string
serverResponse func(w http.ResponseWriter, r *http.Request)
wantErr bool
errContains string
}{
{
name: "successful bookmark creation",
apiToken: "test-token",
orgSlug: "test-org",
tags: "tag1, tag2",
visibility: "PUBLIC",
entryURL: "https://example.com",
entryTitle: "Test Article",
entryContent: "Test content",
serverResponse: func(w http.ResponseWriter, r *http.Request) {
// Verify authorization header
auth := r.Header.Get("Authorization")
if auth != "Bearer test-token" {
t.Errorf("Expected Authorization header 'Bearer test-token', got %s", auth)
}
// Verify content type
contentType := r.Header.Get("Content-Type")
if contentType != "application/json" {
t.Errorf("Expected Content-Type 'application/json', got %s", contentType)
}
// Parse and verify request
body, _ := io.ReadAll(r.Body)
var req map[string]interface{}
if err := json.Unmarshal(body, &req); err != nil {
t.Errorf("Failed to parse request body: %v", err)
}
// Verify mutation exists
if _, ok := req["query"]; !ok {
t.Error("Missing 'query' field in request")
}
// Return success response
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"data": map[string]interface{}{
"addLink": map[string]interface{}{
"id": "123",
"url": "https://example.com",
"title": "Test Article",
},
},
})
},
wantErr: false,
},
{
name: "missing API token",
apiToken: "",
orgSlug: "test-org",
entryURL: "https://example.com",
entryTitle: "Test",
entryContent: "Content",
serverResponse: func(w http.ResponseWriter, r *http.Request) {
// Should not be called
t.Error("Server should not be called when API token is missing")
},
wantErr: true,
errContains: "missing API token or organization slug",
},
{
name: "missing organization slug",
apiToken: "test-token",
orgSlug: "",
entryURL: "https://example.com",
entryTitle: "Test",
entryContent: "Content",
serverResponse: func(w http.ResponseWriter, r *http.Request) {
// Should not be called
t.Error("Server should not be called when org slug is missing")
},
wantErr: true,
errContains: "missing API token or organization slug",
},
{
name: "GraphQL error response",
apiToken: "test-token",
orgSlug: "test-org",
entryURL: "https://example.com",
entryTitle: "Test",
entryContent: "Content",
serverResponse: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"errors": []interface{}{
map[string]interface{}{
"message": "Invalid input",
},
},
})
},
wantErr: true,
errContains: "Invalid input",
},
{
name: "HTTP error status",
apiToken: "test-token",
orgSlug: "test-org",
entryURL: "https://example.com",
entryTitle: "Test",
entryContent: "Content",
serverResponse: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
},
wantErr: true,
errContains: "status=401",
},
{
name: "private visibility permission error",
apiToken: "test-token",
orgSlug: "test-org",
visibility: "PRIVATE",
entryURL: "https://example.com",
entryTitle: "Test",
entryContent: "Content",
serverResponse: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"errors": []interface{}{
map[string]interface{}{
"message": "PRIVATE visibility requires a paid LinkTaco account",
},
},
})
},
wantErr: true,
errContains: "PRIVATE visibility requires a paid LinkTaco account",
},
{
name: "content truncation",
apiToken: "test-token",
orgSlug: "test-org",
entryURL: "https://example.com",
entryTitle: "Test",
entryContent: strings.Repeat("a", 600), // Content longer than 500 chars
serverResponse: func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
var req map[string]interface{}
json.Unmarshal(body, &req)
// Check that description was truncated
variables := req["variables"].(map[string]interface{})
input := variables["input"].(map[string]interface{})
description := input["description"].(string)
if len(description) != maxDescriptionLength {
t.Errorf("Expected description length %d, got %d", maxDescriptionLength, len(description))
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"data": map[string]interface{}{
"addLink": map[string]interface{}{"id": "123"},
},
})
},
wantErr: false,
},
{
name: "tag limiting",
apiToken: "test-token",
orgSlug: "test-org",
tags: "tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,tag11,tag12",
entryURL: "https://example.com",
entryTitle: "Test",
entryContent: "Content",
serverResponse: func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
var req map[string]interface{}
json.Unmarshal(body, &req)
// Check that only 10 tags were sent
variables := req["variables"].(map[string]interface{})
input := variables["input"].(map[string]interface{})
tags := input["tags"].(string)
tagCount := len(strings.Split(tags, ","))
if tagCount != maxTags {
t.Errorf("Expected %d tags, got %d", maxTags, tagCount)
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"data": map[string]interface{}{
"addLink": map[string]interface{}{"id": "123"},
},
})
},
wantErr: false,
},
{
name: "invalid JSON response",
apiToken: "test-token",
orgSlug: "test-org",
entryURL: "https://example.com",
entryTitle: "Test",
entryContent: "Content",
serverResponse: func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("invalid json"))
},
wantErr: true,
errContains: "unable to decode response",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create test server if we have a server response function
var serverURL string
if tt.serverResponse != nil {
server := httptest.NewServer(http.HandlerFunc(tt.serverResponse))
defer server.Close()
serverURL = server.URL
}
// Create client with test server URL
client := &Client{
graphqlURL: serverURL,
apiToken: tt.apiToken,
orgSlug: tt.orgSlug,
tags: tt.tags,
visibility: tt.visibility,
}
// Call CreateBookmark
err := client.CreateBookmark(tt.entryURL, tt.entryTitle, tt.entryContent)
// Check error expectations
if tt.wantErr {
if err == nil {
t.Errorf("Expected error but got none")
} else if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) {
t.Errorf("Expected error containing '%s', got '%s'", tt.errContains, err.Error())
}
} else {
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
}
})
}
}
func TestNewClient(t *testing.T) {
tests := []struct {
name string
apiToken string
orgSlug string
tags string
visibility string
expectedVisibility string
}{
{
name: "with all parameters",
apiToken: "token",
orgSlug: "org",
tags: "tag1,tag2",
visibility: "PRIVATE",
expectedVisibility: "PRIVATE",
},
{
name: "empty visibility defaults to PUBLIC",
apiToken: "token",
orgSlug: "org",
tags: "tag1",
visibility: "",
expectedVisibility: "PUBLIC",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := NewClient(tt.apiToken, tt.orgSlug, tt.tags, tt.visibility)
if client.apiToken != tt.apiToken {
t.Errorf("Expected apiToken %s, got %s", tt.apiToken, client.apiToken)
}
if client.orgSlug != tt.orgSlug {
t.Errorf("Expected orgSlug %s, got %s", tt.orgSlug, client.orgSlug)
}
if client.tags != tt.tags {
t.Errorf("Expected tags %s, got %s", tt.tags, client.tags)
}
if client.visibility != tt.expectedVisibility {
t.Errorf("Expected visibility %s, got %s", tt.expectedVisibility, client.visibility)
}
if client.graphqlURL != defaultGraphQLURL {
t.Errorf("Expected graphqlURL %s, got %s", defaultGraphQLURL, client.graphqlURL)
}
})
}
}
func TestGraphQLMutation(t *testing.T) {
// Test that the GraphQL mutation is properly formatted
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
var req map[string]interface{}
if err := json.Unmarshal(body, &req); err != nil {
t.Fatalf("Failed to parse request: %v", err)
}
// Verify mutation structure
query, ok := req["query"].(string)
if !ok {
t.Fatal("Missing query field")
}
// Check that mutation contains expected parts
if !strings.Contains(query, "mutation AddLink") {
t.Error("Mutation should contain 'mutation AddLink'")
}
if !strings.Contains(query, "$input: LinkInput!") {
t.Error("Mutation should contain input parameter")
}
if !strings.Contains(query, "addLink(input: $input)") {
t.Error("Mutation should contain addLink call")
}
// Verify variables structure
variables, ok := req["variables"].(map[string]interface{})
if !ok {
t.Fatal("Missing variables field")
}
input, ok := variables["input"].(map[string]interface{})
if !ok {
t.Fatal("Missing input in variables")
}
// Check all required fields
requiredFields := []string{"url", "title", "description", "orgSlug", "visibility", "unread", "starred", "archive", "tags"}
for _, field := range requiredFields {
if _, ok := input[field]; !ok {
t.Errorf("Missing required field: %s", field)
}
}
// Return success
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"data": map[string]interface{}{
"addLink": map[string]interface{}{
"id": "123",
},
},
})
}))
defer server.Close()
client := &Client{
graphqlURL: server.URL,
apiToken: "test-token",
orgSlug: "test-org",
tags: "test",
visibility: "PUBLIC",
}
err := client.CreateBookmark("https://example.com", "Test Title", "Test Content")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
}
func BenchmarkCreateBookmark(b *testing.B) {
// Create a mock server that always returns success
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"data": map[string]interface{}{
"addLink": map[string]interface{}{
"id": "123",
},
},
})
}))
defer server.Close()
client := &Client{
graphqlURL: server.URL,
apiToken: "test-token",
orgSlug: "test-org",
tags: "tag1,tag2,tag3",
visibility: "PUBLIC",
}
// Run benchmark
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = client.CreateBookmark("https://example.com", "Test Title", "Test Content")
}
}
func BenchmarkTagProcessing(b *testing.B) {
// Benchmark tag splitting and limiting
tags := "tag1,tag2,tag3,tag4,tag5,tag6,tag7,tag8,tag9,tag10,tag11,tag12,tag13,tag14,tag15"
b.ResetTimer()
for i := 0; i < b.N; i++ {
tagsSplitFn := func(c rune) bool {
return c == ',' || c == ' '
}
splitTags := strings.FieldsFunc(tags, tagsSplitFn)
if len(splitTags) > maxTags {
splitTags = splitTags[:maxTags]
}
_ = strings.Join(splitTags, ",")
}
}

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Sie müssen ein Passwort festlegen, sonst können Sie sich nicht erneut anmelden.", "error.unlink_account_without_password": "Sie müssen ein Passwort festlegen, sonst können Sie sich nicht erneut anmelden.",
"error.user_already_exists": "Dieser Benutzer existiert bereits.", "error.user_already_exists": "Dieser Benutzer existiert bereits.",
"error.user_mandatory_fields": "Der Benutzername ist obligatorisch.", "error.user_mandatory_fields": "Der Benutzername ist obligatorisch.",
"error.linktaco_missing_required_fields": "LinkTaco API Token und Organization Slug sind erforderlich.",
"form.api_key.label.description": "API-Schlüsselbezeichnung", "form.api_key.label.description": "API-Schlüsselbezeichnung",
"form.category.hide_globally": "Einträge in der globalen Ungelesen-Liste ausblenden", "form.category.hide_globally": "Einträge in der globalen Ungelesen-Liste ausblenden",
"form.category.label.title": "Titel", "form.category.label.title": "Titel",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Lesezeichen als ungelesen markieren", "form.integration.linkding_bookmark": "Lesezeichen als ungelesen markieren",
"form.integration.linkding_endpoint": "Linkding-API-Endpunkt", "form.integration.linkding_endpoint": "Linkding-API-Endpunkt",
"form.integration.linkding_tags": "Linkding-Tags", "form.integration.linkding_tags": "Linkding-Tags",
"form.integration.linktaco_activate": "Einträge in LinkTaco speichern",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Holen Sie sich Ihr persönliches Zugriffstoken unter",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Tags (max. 10, kommagetrennt)",
"form.integration.linktaco_tags_hint": "Maximal 10 Tags, kommagetrennt",
"form.integration.linktaco_visibility": "Sichtbarkeit",
"form.integration.linktaco_visibility_public": "Öffentlich",
"form.integration.linktaco_visibility_private": "Privat",
"form.integration.linktaco_visibility_hint": "PRIVATE Sichtbarkeit erfordert ein kostenpflichtiges LinkTaco-Konto",
"form.integration.linkwarden_activate": "Artikel in Linkwarden speichern", "form.integration.linkwarden_activate": "Artikel in Linkwarden speichern",
"form.integration.linkwarden_api_key": "Linkwarden-API-Schlüssel", "form.integration.linkwarden_api_key": "Linkwarden-API-Schlüssel",
"form.integration.linkwarden_endpoint": "Linkwarden-Base-URL", "form.integration.linkwarden_endpoint": "Linkwarden-Base-URL",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Πρέπει να ορίσετε έναν κωδικό πρόσβασης διαφορετικά δεν θα μπορείτε να συνδεθείτε ξανά.", "error.unlink_account_without_password": "Πρέπει να ορίσετε έναν κωδικό πρόσβασης διαφορετικά δεν θα μπορείτε να συνδεθείτε ξανά.",
"error.user_already_exists": "Αυτός ο χρήστης υπάρχει ήδη.", "error.user_already_exists": "Αυτός ο χρήστης υπάρχει ήδη.",
"error.user_mandatory_fields": "Το όνομα χρήστη είναι υποχρεωτικό.", "error.user_mandatory_fields": "Το όνομα χρήστη είναι υποχρεωτικό.",
"error.linktaco_missing_required_fields": "Το LinkTaco API Token και το Organization Slug είναι απαραίτητα",
"form.api_key.label.description": "Ετικέτα κλειδιού API", "form.api_key.label.description": "Ετικέτα κλειδιού API",
"form.category.hide_globally": "Απόκρυψη καταχωρήσεων σε γενική λίστα μη αναγνωσμένων", "form.category.hide_globally": "Απόκρυψη καταχωρήσεων σε γενική λίστα μη αναγνωσμένων",
"form.category.label.title": "Τίτλος", "form.category.label.title": "Τίτλος",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Σημείωση του σελιδοδείκτη ως μη αναγνωσμένου", "form.integration.linkding_bookmark": "Σημείωση του σελιδοδείκτη ως μη αναγνωσμένου",
"form.integration.linkding_endpoint": "Τελικό σημείο Linkding API", "form.integration.linkding_endpoint": "Τελικό σημείο Linkding API",
"form.integration.linkding_tags": "Ετικέτες Linkding", "form.integration.linkding_tags": "Ετικέτες Linkding",
"form.integration.linktaco_activate": "Αποθήκευση καταχωρήσεων στο LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Λάβετε το προσωπικό σας διακριτικό πρόσβασης στο",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Ετικέτες (μέγιστο 10, διαχωρισμένες με κόμμα)",
"form.integration.linktaco_tags_hint": "Μέγιστο 10 ετικέτες, διαχωρισμένες με κόμμα",
"form.integration.linktaco_visibility": "Ορατότητα",
"form.integration.linktaco_visibility_public": "Δημόσια",
"form.integration.linktaco_visibility_private": "Ιδιωτική",
"form.integration.linktaco_visibility_hint": "Η ΙΔΙΩΤΙΚΗ ορατότητα απαιτεί επί πληρωμή λογαριασμό LinkTaco",
"form.integration.linkwarden_activate": "Αποθήκευση άρθρων στο Linkwarden", "form.integration.linkwarden_activate": "Αποθήκευση άρθρων στο Linkwarden",
"form.integration.linkwarden_api_key": "Κλειδί API Linkwarden", "form.integration.linkwarden_api_key": "Κλειδί API Linkwarden",
"form.integration.linkwarden_endpoint": "URL βάσης Linkwarden", "form.integration.linkwarden_endpoint": "URL βάσης Linkwarden",

View file

@ -89,6 +89,7 @@
"error.different_passwords": "Passwords are not the same.", "error.different_passwords": "Passwords are not the same.",
"error.duplicate_fever_username": "There is already someone else with the same Fever username!", "error.duplicate_fever_username": "There is already someone else with the same Fever username!",
"error.duplicate_googlereader_username": "There is already someone else with the same Google Reader username!", "error.duplicate_googlereader_username": "There is already someone else with the same Google Reader username!",
"error.linktaco_missing_required_fields": "LinkTaco API Token and Organization Slug are required",
"error.duplicate_linked_account": "There is already someone associated with this provider!", "error.duplicate_linked_account": "There is already someone associated with this provider!",
"error.duplicated_feed": "This feed already exists.", "error.duplicated_feed": "This feed already exists.",
"error.empty_file": "This file is empty.", "error.empty_file": "This file is empty.",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Mark bookmark as unread", "form.integration.linkding_bookmark": "Mark bookmark as unread",
"form.integration.linkding_endpoint": "Linkding API Endpoint", "form.integration.linkding_endpoint": "Linkding API Endpoint",
"form.integration.linkding_tags": "Linkding Tags", "form.integration.linkding_tags": "Linkding Tags",
"form.integration.linktaco_activate": "Save entries to LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Get your personal access token at",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Tags (max 10, comma-separated)",
"form.integration.linktaco_tags_hint": "Maximum 10 tags, comma-separated",
"form.integration.linktaco_visibility": "Visibility",
"form.integration.linktaco_visibility_public": "Public",
"form.integration.linktaco_visibility_private": "Private",
"form.integration.linktaco_visibility_hint": "PRIVATE visibility requires a paid LinkTaco account",
"form.integration.linkwarden_activate": "Save entries to Linkwarden", "form.integration.linkwarden_activate": "Save entries to Linkwarden",
"form.integration.linkwarden_api_key": "Linkwarden API key", "form.integration.linkwarden_api_key": "Linkwarden API key",
"form.integration.linkwarden_endpoint": "Linkwarden Base URL", "form.integration.linkwarden_endpoint": "Linkwarden Base URL",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Debe definir una contraseña, de lo contrario no podrá volver a iniciar sesión.", "error.unlink_account_without_password": "Debe definir una contraseña, de lo contrario no podrá volver a iniciar sesión.",
"error.user_already_exists": "Este usuario ya existe.", "error.user_already_exists": "Este usuario ya existe.",
"error.user_mandatory_fields": "El nombre de usuario es obligatorio.", "error.user_mandatory_fields": "El nombre de usuario es obligatorio.",
"error.linktaco_missing_required_fields": "LinkTaco API Token y Organization Slug son obligatorios.",
"form.api_key.label.description": "Etiqueta de clave API", "form.api_key.label.description": "Etiqueta de clave API",
"form.category.hide_globally": "Ocultar artículos en la lista global de no leídos", "form.category.hide_globally": "Ocultar artículos en la lista global de no leídos",
"form.category.label.title": "Título", "form.category.label.title": "Título",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Marcar marcador como no leído", "form.integration.linkding_bookmark": "Marcar marcador como no leído",
"form.integration.linkding_endpoint": "Acceso API de Linkding", "form.integration.linkding_endpoint": "Acceso API de Linkding",
"form.integration.linkding_tags": "Etiquetas de Linkding", "form.integration.linkding_tags": "Etiquetas de Linkding",
"form.integration.linktaco_activate": "Guardar entradas en LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Obtenga su token de acceso personal en",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Etiquetas (máx. 10, separadas por comas)",
"form.integration.linktaco_tags_hint": "Máximo 10 etiquetas, separadas por comas",
"form.integration.linktaco_visibility": "Visibilidad",
"form.integration.linktaco_visibility_public": "Público",
"form.integration.linktaco_visibility_private": "Privado",
"form.integration.linktaco_visibility_hint": "La visibilidad PRIVADA requiere una cuenta de pago de LinkTaco",
"form.integration.linkwarden_activate": "Enviar artículos a Linkwarden", "form.integration.linkwarden_activate": "Enviar artículos a Linkwarden",
"form.integration.linkwarden_api_key": "Clave de API de Linkwarden", "form.integration.linkwarden_api_key": "Clave de API de Linkwarden",
"form.integration.linkwarden_endpoint": "URL base de Linkwarden", "form.integration.linkwarden_endpoint": "URL base de Linkwarden",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Sinun on määritettävä salasana, muuten et voi kirjautua uudelleen.", "error.unlink_account_without_password": "Sinun on määritettävä salasana, muuten et voi kirjautua uudelleen.",
"error.user_already_exists": "Käyttäjä on jo olemassa.", "error.user_already_exists": "Käyttäjä on jo olemassa.",
"error.user_mandatory_fields": "Käyttäjätunnus on pakollinen.", "error.user_mandatory_fields": "Käyttäjätunnus on pakollinen.",
"error.linktaco_missing_required_fields": "LinkTaco API Token ja Organization Slug vaaditaan",
"form.api_key.label.description": "API Key Label", "form.api_key.label.description": "API Key Label",
"form.category.hide_globally": "Piilota artikkelit lukemattomien listassa", "form.category.hide_globally": "Piilota artikkelit lukemattomien listassa",
"form.category.label.title": "Otsikko", "form.category.label.title": "Otsikko",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Merkitse kirjanmerkki lukemattomaksi", "form.integration.linkding_bookmark": "Merkitse kirjanmerkki lukemattomaksi",
"form.integration.linkding_endpoint": "Linkding API-päätepiste", "form.integration.linkding_endpoint": "Linkding API-päätepiste",
"form.integration.linkding_tags": "Linkding Tags", "form.integration.linkding_tags": "Linkding Tags",
"form.integration.linktaco_activate": "Tallenna kirjoituksia LinkTacoon",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Hanki henkilökohtainen pääsytunnistesi osoitteesta",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Tagit (enintään 10, pilkuilla erotettu)",
"form.integration.linktaco_tags_hint": "Enintään 10 tagia, pilkuilla erotettu",
"form.integration.linktaco_visibility": "Näkyvyys",
"form.integration.linktaco_visibility_public": "Julkinen",
"form.integration.linktaco_visibility_private": "Yksityinen",
"form.integration.linktaco_visibility_hint": "YKSITYINEN näkyvyys vaatii maksullisen LinkTaco-tilin",
"form.integration.linkwarden_activate": "Tallenna artikkelit Linkkiin", "form.integration.linkwarden_activate": "Tallenna artikkelit Linkkiin",
"form.integration.linkwarden_api_key": "Linkwarden API-avain", "form.integration.linkwarden_api_key": "Linkwarden API-avain",
"form.integration.linkwarden_endpoint": "Linkwarden Base URL", "form.integration.linkwarden_endpoint": "Linkwarden Base URL",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Vous devez définir un mot de passe sinon vous ne pourrez plus vous connecter par la suite.", "error.unlink_account_without_password": "Vous devez définir un mot de passe sinon vous ne pourrez plus vous connecter par la suite.",
"error.user_already_exists": "Cet utilisateur existe déjà.", "error.user_already_exists": "Cet utilisateur existe déjà.",
"error.user_mandatory_fields": "Le nom d'utilisateur est obligatoire.", "error.user_mandatory_fields": "Le nom d'utilisateur est obligatoire.",
"error.linktaco_missing_required_fields": "Le token API LinkTaco et le slug de l'organisation sont requis.",
"form.api_key.label.description": "Libellé de la clé d'API", "form.api_key.label.description": "Libellé de la clé d'API",
"form.category.hide_globally": "Masquer les entrées dans la liste globale non lue", "form.category.hide_globally": "Masquer les entrées dans la liste globale non lue",
"form.category.label.title": "Titre", "form.category.label.title": "Titre",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Marquer le lien comme non lu", "form.integration.linkding_bookmark": "Marquer le lien comme non lu",
"form.integration.linkding_endpoint": "URL de l'API de Linkding", "form.integration.linkding_endpoint": "URL de l'API de Linkding",
"form.integration.linkding_tags": "Libellés", "form.integration.linkding_tags": "Libellés",
"form.integration.linktaco_activate": "Sauvegarder les entrées vers LinkTaco",
"form.integration.linktaco_api_token": "Token API LinkTaco",
"form.integration.linktaco_api_token_hint": "Obtenez votre token d'accès personnel sur",
"form.integration.linktaco_org_slug": "Slug de l'organisation",
"form.integration.linktaco_tags": "Tags (max. 10, séparés par des virgules)",
"form.integration.linktaco_tags_hint": "Maximum 10 tags, séparés par des virgules",
"form.integration.linktaco_visibility": "Visibilité",
"form.integration.linktaco_visibility_public": "Public",
"form.integration.linktaco_visibility_private": "Privé",
"form.integration.linktaco_visibility_hint": "La visibilité PRIVÉE nécessite un compte LinkTaco payant",
"form.integration.linkwarden_activate": "Sauvegarder les articles vers Linkwarden", "form.integration.linkwarden_activate": "Sauvegarder les articles vers Linkwarden",
"form.integration.linkwarden_api_key": "Clé d'API de Linkwarden", "form.integration.linkwarden_api_key": "Clé d'API de Linkwarden",
"form.integration.linkwarden_endpoint": "URL de base de Linkwarden", "form.integration.linkwarden_endpoint": "URL de base de Linkwarden",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "आपको एक पासवर्ड परिभाषित करना होगा अन्यथा आप फिर से लॉगिन नहीं कर पाएंगे।", "error.unlink_account_without_password": "आपको एक पासवर्ड परिभाषित करना होगा अन्यथा आप फिर से लॉगिन नहीं कर पाएंगे।",
"error.user_already_exists": "यह उपयोगकर्ता पहले से ही मौजूद है।", "error.user_already_exists": "यह उपयोगकर्ता पहले से ही मौजूद है।",
"error.user_mandatory_fields": "उपयोगकर्ता नाम अनिवार्य है।", "error.user_mandatory_fields": "उपयोगकर्ता नाम अनिवार्य है।",
"error.linktaco_missing_required_fields": "LinkTaco API Token और Organization Slug आवश्यक हैं",
"form.api_key.label.description": "एपीआई कुंजी लेबल", "form.api_key.label.description": "एपीआई कुंजी लेबल",
"form.category.hide_globally": "वैश्विक अपठित सूची में प्रविष्टियां छिपाएं", "form.category.hide_globally": "वैश्विक अपठित सूची में प्रविष्टियां छिपाएं",
"form.category.label.title": "शीर्षक", "form.category.label.title": "शीर्षक",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "बुकमार्क को अपठित के रूप में चिह्नित करें", "form.integration.linkding_bookmark": "बुकमार्क को अपठित के रूप में चिह्नित करें",
"form.integration.linkding_endpoint": "लिंकिंग एपीआई समापन बिंदु", "form.integration.linkding_endpoint": "लिंकिंग एपीआई समापन बिंदु",
"form.integration.linkding_tags": "Linkding Tags", "form.integration.linkding_tags": "Linkding Tags",
"form.integration.linktaco_activate": "LinkTaco में प्रविष्टियाँ सहेजें",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "अपना व्यक्तिगत पहुँच टोकन प्राप्त करें",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "टैग (अधिकतम 10, कॉमा से अलग किए गए)",
"form.integration.linktaco_tags_hint": "अधिकतम 10 टैग, कॉमा से अलग किए गए",
"form.integration.linktaco_visibility": "दृश्यता",
"form.integration.linktaco_visibility_public": "सार्वजनिक",
"form.integration.linktaco_visibility_private": "निजी",
"form.integration.linktaco_visibility_hint": "निजी दृश्यता के लिए भुगतान LinkTaco खाता आवश्यक है",
"form.integration.linkwarden_activate": "Save entries to Linkwarden", "form.integration.linkwarden_activate": "Save entries to Linkwarden",
"form.integration.linkwarden_api_key": "Linkwarden API key", "form.integration.linkwarden_api_key": "Linkwarden API key",
"form.integration.linkwarden_endpoint": "लिंकवर्डन बेस यूआरएलL", "form.integration.linkwarden_endpoint": "लिंकवर्डन बेस यूआरएलL",

View file

@ -157,6 +157,7 @@
"error.unlink_account_without_password": "Anda harus mengatur kata sandi atau Anda tidak bisa masuk kembali.", "error.unlink_account_without_password": "Anda harus mengatur kata sandi atau Anda tidak bisa masuk kembali.",
"error.user_already_exists": "Pengguna ini sudah ada.", "error.user_already_exists": "Pengguna ini sudah ada.",
"error.user_mandatory_fields": "Harus ada nama pengguna.", "error.user_mandatory_fields": "Harus ada nama pengguna.",
"error.linktaco_missing_required_fields": "LinkTaco API Token dan Organization Slug diperlukan",
"form.api_key.label.description": "Label Kunci API", "form.api_key.label.description": "Label Kunci API",
"form.category.hide_globally": "Sembunyikan entri di daftar belum dibaca global", "form.category.hide_globally": "Sembunyikan entri di daftar belum dibaca global",
"form.category.label.title": "Judul", "form.category.label.title": "Judul",
@ -247,6 +248,16 @@
"form.integration.linkding_bookmark": "Tandai markah sebagai belum dibaca", "form.integration.linkding_bookmark": "Tandai markah sebagai belum dibaca",
"form.integration.linkding_endpoint": "Titik URL API Linkding", "form.integration.linkding_endpoint": "Titik URL API Linkding",
"form.integration.linkding_tags": "Tanda Linkding", "form.integration.linkding_tags": "Tanda Linkding",
"form.integration.linktaco_activate": "Simpan entri ke LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Dapatkan token akses pribadi Anda di",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Tag (maksimal 10, dipisahkan koma)",
"form.integration.linktaco_tags_hint": "Maksimal 10 tag, dipisahkan koma",
"form.integration.linktaco_visibility": "Visibilitas",
"form.integration.linktaco_visibility_public": "Publik",
"form.integration.linktaco_visibility_private": "Pribadi",
"form.integration.linktaco_visibility_hint": "Visibilitas PRIBADI membutuhkan akun LinkTaco berbayar",
"form.integration.linkwarden_activate": "Simpan artikel ke Linkwarden", "form.integration.linkwarden_activate": "Simpan artikel ke Linkwarden",
"form.integration.linkwarden_api_key": "Kunci API Linkwarden", "form.integration.linkwarden_api_key": "Kunci API Linkwarden",
"form.integration.linkwarden_endpoint": "URL Dasar Linkwarden", "form.integration.linkwarden_endpoint": "URL Dasar Linkwarden",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Devi scegliere una password altrimenti la prossima volta non riuscirai ad accedere.", "error.unlink_account_without_password": "Devi scegliere una password altrimenti la prossima volta non riuscirai ad accedere.",
"error.user_already_exists": "Questo utente esiste già.", "error.user_already_exists": "Questo utente esiste già.",
"error.user_mandatory_fields": "Il nome utente è obbligatorio.", "error.user_mandatory_fields": "Il nome utente è obbligatorio.",
"error.linktaco_missing_required_fields": "LinkTaco API Token e Organization Slug sono richiesti",
"form.api_key.label.description": "Etichetta chiave API", "form.api_key.label.description": "Etichetta chiave API",
"form.category.hide_globally": "Nascondere le voci nella lista globale dei non letti", "form.category.hide_globally": "Nascondere le voci nella lista globale dei non letti",
"form.category.label.title": "Titolo", "form.category.label.title": "Titolo",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Segna i preferiti come non letti", "form.integration.linkding_bookmark": "Segna i preferiti come non letti",
"form.integration.linkding_endpoint": "Endpoint dell'API di Linkding", "form.integration.linkding_endpoint": "Endpoint dell'API di Linkding",
"form.integration.linkding_tags": "Linkding Tags", "form.integration.linkding_tags": "Linkding Tags",
"form.integration.linktaco_activate": "Salva le voci in LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Ottieni il tuo token di accesso personale su",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Tag (massimo 10, separati da virgola)",
"form.integration.linktaco_tags_hint": "Massimo 10 tag, separati da virgola",
"form.integration.linktaco_visibility": "Visibilità",
"form.integration.linktaco_visibility_public": "Pubblico",
"form.integration.linktaco_visibility_private": "Privato",
"form.integration.linktaco_visibility_hint": "La visibilità PRIVATA richiede un account LinkTaco a pagamento",
"form.integration.linkwarden_activate": "Salva gli articoli su Linkwarden", "form.integration.linkwarden_activate": "Salva gli articoli su Linkwarden",
"form.integration.linkwarden_api_key": "API key dell'account Linkwarden", "form.integration.linkwarden_api_key": "API key dell'account Linkwarden",
"form.integration.linkwarden_endpoint": "URL di base di Linkwarden", "form.integration.linkwarden_endpoint": "URL di base di Linkwarden",

View file

@ -157,6 +157,7 @@
"error.unlink_account_without_password": "パスワードを設定しなければ再びログインすることはできません。", "error.unlink_account_without_password": "パスワードを設定しなければ再びログインすることはできません。",
"error.user_already_exists": "このユーザーは既に存在します。", "error.user_already_exists": "このユーザーは既に存在します。",
"error.user_mandatory_fields": "ユーザー名が必要です。", "error.user_mandatory_fields": "ユーザー名が必要です。",
"error.linktaco_missing_required_fields": "LinkTaco API TokenとOrganization Slugが必要です",
"form.api_key.label.description": "API キーラベル", "form.api_key.label.description": "API キーラベル",
"form.category.hide_globally": "未読一覧に記事を表示しない", "form.category.hide_globally": "未読一覧に記事を表示しない",
"form.category.label.title": "タイトル", "form.category.label.title": "タイトル",
@ -247,6 +248,16 @@
"form.integration.linkding_bookmark": "ブックマークを未読にする", "form.integration.linkding_bookmark": "ブックマークを未読にする",
"form.integration.linkding_endpoint": "Linkding の API Endpoint", "form.integration.linkding_endpoint": "Linkding の API Endpoint",
"form.integration.linkding_tags": "Linkding Tags", "form.integration.linkding_tags": "Linkding Tags",
"form.integration.linktaco_activate": "LinkTacoでエントリを保存する",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "パーソナルアクセストークンを取得する",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "タグ (最大10件、カンマ区切り)",
"form.integration.linktaco_tags_hint": "最大10件のタグ、カンマ区切り",
"form.integration.linktaco_visibility": "公開設定",
"form.integration.linktaco_visibility_public": "公開",
"form.integration.linktaco_visibility_private": "非公開",
"form.integration.linktaco_visibility_hint": "非公開設定には有料のLinkTacoアカウントが必要です",
"form.integration.linkwarden_activate": "Linkwarden に記事を保存する", "form.integration.linkwarden_activate": "Linkwarden に記事を保存する",
"form.integration.linkwarden_api_key": "Linkwarden の API key", "form.integration.linkwarden_api_key": "Linkwarden の API key",
"form.integration.linkwarden_endpoint": "リンクワーデン ベース URL", "form.integration.linkwarden_endpoint": "リンクワーデン ベース URL",

View file

@ -157,6 +157,7 @@
"error.unlink_account_without_password": "Lí it-tēng ài siat-tēng bi̍t-bé, bô lí ē bô-hoat-tō͘ koh teng-lo̍k.", "error.unlink_account_without_password": "Lí it-tēng ài siat-tēng bi̍t-bé, bô lí ē bô-hoat-tō͘ koh teng-lo̍k.",
"error.user_already_exists": "Chit ê sú-iōng-lâng í-keng chûn-chāi.", "error.user_already_exists": "Chit ê sú-iōng-lâng í-keng chûn-chāi.",
"error.user_mandatory_fields": "Tio̍h-ài su-li̍p kháu-chō miâ", "error.user_mandatory_fields": "Tio̍h-ài su-li̍p kháu-chō miâ",
"error.linktaco_missing_required_fields": "LinkTaco API Token kâh Organization Slug sio̍kêi",
"form.api_key.label.description": "API só-sîkhan-á", "form.api_key.label.description": "API só-sîkhan-á",
"form.category.hide_globally": "Mài hián-sī siau-sit tī choân-he̍k ah-bōe tha̍k lia̍t-pió lāi", "form.category.hide_globally": "Mài hián-sī siau-sit tī choân-he̍k ah-bōe tha̍k lia̍t-pió lāi",
"form.category.label.title": "Piau-tôe", "form.category.label.title": "Piau-tôe",
@ -247,6 +248,16 @@
"form.integration.linkding_bookmark": "Chù chòe ah-bōe tha̍k", "form.integration.linkding_bookmark": "Chù chòe ah-bōe tha̍k",
"form.integration.linkding_endpoint": "Linkding API thâu", "form.integration.linkding_endpoint": "Linkding API thâu",
"form.integration.linkding_tags": "Linkding khan-á", "form.integration.linkding_tags": "Linkding khan-á",
"form.integration.linktaco_activate": "Pó-chûn siau-sit kàu LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Chhú-tek lí ê kò-jîn chún-chhú token tī",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "khan-á (siōn-koân 10, iōng tō͘-tiám keh khui)",
"form.integration.linktaco_tags_hint": "Siōn-koân 10 khan-á, iōng tō͘-tiám keh khui",
"form.integration.linktaco_visibility": "Kò-chhiah-kì sìa?",
"form.integration.linktaco_visibility_public": "Kò-chhiah-kì",
"form.integration.linktaco_visibility_private": "Su-lîn",
"form.integration.linktaco_visibility_hint": "Su-lîn sìa tík tio̍h-ài chù-hêng LinkTaco kháu-chō",
"form.integration.linkwarden_activate": "Pó-chûn siau-sit kàu Linkwarden", "form.integration.linkwarden_activate": "Pó-chûn siau-sit kàu Linkwarden",
"form.integration.linkwarden_api_key": "Linkwarden API só-sî", "form.integration.linkwarden_api_key": "Linkwarden API só-sî",
"form.integration.linkwarden_endpoint": "Linkwarden Base URL", "form.integration.linkwarden_endpoint": "Linkwarden Base URL",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Je moet een wachtwoord opgeven anders kun je niet meer inloggen.", "error.unlink_account_without_password": "Je moet een wachtwoord opgeven anders kun je niet meer inloggen.",
"error.user_already_exists": "Deze gebruiker bestaat al.", "error.user_already_exists": "Deze gebruiker bestaat al.",
"error.user_mandatory_fields": "Gebruikersnaam is verplicht", "error.user_mandatory_fields": "Gebruikersnaam is verplicht",
"error.linktaco_missing_required_fields": "LinkTaco API Token en Organization Slug zijn verplicht",
"form.api_key.label.description": "API-sleutel omschrijving", "form.api_key.label.description": "API-sleutel omschrijving",
"form.category.hide_globally": "Verberg artikelen in de globale ongelezen lijst", "form.category.hide_globally": "Verberg artikelen in de globale ongelezen lijst",
"form.category.label.title": "Titel", "form.category.label.title": "Titel",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Markeer favoriet als ongelezen", "form.integration.linkding_bookmark": "Markeer favoriet als ongelezen",
"form.integration.linkding_endpoint": "Linkding URL", "form.integration.linkding_endpoint": "Linkding URL",
"form.integration.linkding_tags": "Linkding tags", "form.integration.linkding_tags": "Linkding tags",
"form.integration.linktaco_activate": "Artikelen opslaan in LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Verkrijg uw persoonlijke toegangstoken op",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Tags (max 10, kommagescheiden)",
"form.integration.linktaco_tags_hint": "Maximaal 10 tags, kommagescheiden",
"form.integration.linktaco_visibility": "Zichtbaarheid",
"form.integration.linktaco_visibility_public": "Openbaar",
"form.integration.linktaco_visibility_private": "Privé",
"form.integration.linktaco_visibility_hint": "PRIVÉ zichtbaarheid vereist een betaald LinkTaco account",
"form.integration.linkwarden_activate": "Artikelen opslaan in Linkwarden", "form.integration.linkwarden_activate": "Artikelen opslaan in Linkwarden",
"form.integration.linkwarden_api_key": "Linkwarden API-sleutel", "form.integration.linkwarden_api_key": "Linkwarden API-sleutel",
"form.integration.linkwarden_endpoint": "Linkwarden Basis URL", "form.integration.linkwarden_endpoint": "Linkwarden Basis URL",

View file

@ -163,6 +163,7 @@
"error.unlink_account_without_password": "Musisz zdefiniować hasło, inaczej nie będziesz mógł się ponownie zalogować.", "error.unlink_account_without_password": "Musisz zdefiniować hasło, inaczej nie będziesz mógł się ponownie zalogować.",
"error.user_already_exists": "Ten użytkownik już istnieje.", "error.user_already_exists": "Ten użytkownik już istnieje.",
"error.user_mandatory_fields": "Nazwa użytkownika jest obowiązkowa.", "error.user_mandatory_fields": "Nazwa użytkownika jest obowiązkowa.",
"error.linktaco_missing_required_fields": "LinkTaco API Token i Organization Slug są wymagane",
"form.api_key.label.description": "Etykieta klucza API", "form.api_key.label.description": "Etykieta klucza API",
"form.category.hide_globally": "Ukryj wpisy na globalnej liście nieprzeczytanych", "form.category.hide_globally": "Ukryj wpisy na globalnej liście nieprzeczytanych",
"form.category.label.title": "Tytuł", "form.category.label.title": "Tytuł",
@ -253,6 +254,16 @@
"form.integration.linkding_bookmark": "Oznacz zakładkę jako nieprzeczytaną", "form.integration.linkding_bookmark": "Oznacz zakładkę jako nieprzeczytaną",
"form.integration.linkding_endpoint": "Punkt końcowy API Linkding", "form.integration.linkding_endpoint": "Punkt końcowy API Linkding",
"form.integration.linkding_tags": "Znaczniki Linkding", "form.integration.linkding_tags": "Znaczniki Linkding",
"form.integration.linktaco_activate": "Zapisuj wpisy w LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Uzyskaj swój osobisty token dostępu w",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Znaczniki (max 10, oddzielone przecinkami)",
"form.integration.linktaco_tags_hint": "Maksymalnie 10 znaczników, oddzielone przecinkami",
"form.integration.linktaco_visibility": "Widoczność",
"form.integration.linktaco_visibility_public": "Publiczne",
"form.integration.linktaco_visibility_private": "Prywatne",
"form.integration.linktaco_visibility_hint": "Widoczność PRYWATNA wymaga płatnego konta LinkTaco",
"form.integration.linkwarden_activate": "Zapisuj wpisy w Linkwarden", "form.integration.linkwarden_activate": "Zapisuj wpisy w Linkwarden",
"form.integration.linkwarden_api_key": "Klucz API do Linkwarden", "form.integration.linkwarden_api_key": "Klucz API do Linkwarden",
"form.integration.linkwarden_endpoint": "Podstawowy adres URL Linkwardena", "form.integration.linkwarden_endpoint": "Podstawowy adres URL Linkwardena",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Você deve definir uma senha, senão não será possível efetuar a sessão novamente.", "error.unlink_account_without_password": "Você deve definir uma senha, senão não será possível efetuar a sessão novamente.",
"error.user_already_exists": "Esse usuário já existe.", "error.user_already_exists": "Esse usuário já existe.",
"error.user_mandatory_fields": "O nome de usuário é obrigatório.", "error.user_mandatory_fields": "O nome de usuário é obrigatório.",
"error.linktaco_missing_required_fields": "LinkTaco API Token e Organization Slug são obrigatórios",
"form.api_key.label.description": "Etiqueta da chave de API", "form.api_key.label.description": "Etiqueta da chave de API",
"form.category.hide_globally": "Ocultar entradas na lista global não lida", "form.category.hide_globally": "Ocultar entradas na lista global não lida",
"form.category.label.title": "Título", "form.category.label.title": "Título",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Salvar marcador como não lido", "form.integration.linkding_bookmark": "Salvar marcador como não lido",
"form.integration.linkding_endpoint": "Endpoint de API do Linkding", "form.integration.linkding_endpoint": "Endpoint de API do Linkding",
"form.integration.linkding_tags": "Linkding Tags", "form.integration.linkding_tags": "Linkding Tags",
"form.integration.linktaco_activate": "Salvar itens no LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Obtenha seu token de acesso pessoal em",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Tags (máx 10, separadas por vírgula)",
"form.integration.linktaco_tags_hint": "Máximo 10 tags, separadas por vírgula",
"form.integration.linktaco_visibility": "Visibilidade",
"form.integration.linktaco_visibility_public": "Público",
"form.integration.linktaco_visibility_private": "Privado",
"form.integration.linktaco_visibility_hint": "Visibilidade PRIVADA requer uma conta LinkTaco paga",
"form.integration.linkwarden_activate": "Salvar itens no Linkwarden", "form.integration.linkwarden_activate": "Salvar itens no Linkwarden",
"form.integration.linkwarden_api_key": "Chave de API do Linkwarden", "form.integration.linkwarden_api_key": "Chave de API do Linkwarden",
"form.integration.linkwarden_endpoint": "URL base do Linkwarden", "form.integration.linkwarden_endpoint": "URL base do Linkwarden",

View file

@ -163,6 +163,7 @@
"error.unlink_account_without_password": "Trebuie să definiți o parolă, altfel nu vă veți mai putea conecta.", "error.unlink_account_without_password": "Trebuie să definiți o parolă, altfel nu vă veți mai putea conecta.",
"error.user_already_exists": "Acest utilizator există deja.", "error.user_already_exists": "Acest utilizator există deja.",
"error.user_mandatory_fields": "Numele utilizatorului este obligatoriu.", "error.user_mandatory_fields": "Numele utilizatorului este obligatoriu.",
"error.linktaco_missing_required_fields": "LinkTaco API Token și Organization Slug sunt necesare",
"form.api_key.label.description": "Etichetă Cheie API", "form.api_key.label.description": "Etichetă Cheie API",
"form.category.hide_globally": "Ascunde intrările în lista globală de articole necitite", "form.category.hide_globally": "Ascunde intrările în lista globală de articole necitite",
"form.category.label.title": "Titlu", "form.category.label.title": "Titlu",
@ -253,6 +254,16 @@
"form.integration.linkding_bookmark": "Marchează semnele de carte ca necitite", "form.integration.linkding_bookmark": "Marchează semnele de carte ca necitite",
"form.integration.linkding_endpoint": "Endpoint API Linkding", "form.integration.linkding_endpoint": "Endpoint API Linkding",
"form.integration.linkding_tags": "TAG-uri Linkding", "form.integration.linkding_tags": "TAG-uri Linkding",
"form.integration.linktaco_activate": "Salvează înregistrările în LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Obțineți jetonul de acces personal la",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Tag-uri (maxim 10, separate prin virgule)",
"form.integration.linktaco_tags_hint": "Maxim 10 tag-uri, separate prin virgule",
"form.integration.linktaco_visibility": "Vizibilitate",
"form.integration.linktaco_visibility_public": "Public",
"form.integration.linktaco_visibility_private": "Privat",
"form.integration.linktaco_visibility_hint": "Vizibilitatea PRIVATĂ necesită un cont LinkTaco plătit",
"form.integration.linkwarden_activate": "Salvează intrările în Linkwarden", "form.integration.linkwarden_activate": "Salvează intrările în Linkwarden",
"form.integration.linkwarden_api_key": "Cheie API Linkwarden", "form.integration.linkwarden_api_key": "Cheie API Linkwarden",
"form.integration.linkwarden_endpoint": "URL-ul de bază Linkwarden", "form.integration.linkwarden_endpoint": "URL-ul de bază Linkwarden",

View file

@ -163,6 +163,7 @@
"error.unlink_account_without_password": "Вы должны установить пароль, иначе вы не сможете войти снова.", "error.unlink_account_without_password": "Вы должны установить пароль, иначе вы не сможете войти снова.",
"error.user_already_exists": "Этот пользователь уже существует.", "error.user_already_exists": "Этот пользователь уже существует.",
"error.user_mandatory_fields": "Имя пользователя обязательно.", "error.user_mandatory_fields": "Имя пользователя обязательно.",
"error.linktaco_missing_required_fields": "LinkTaco API Token и Organization Slug обязательны",
"form.api_key.label.description": "Описание API-ключа", "form.api_key.label.description": "Описание API-ключа",
"form.category.hide_globally": "Скрыть записи в глобальном списке непрочитанных", "form.category.hide_globally": "Скрыть записи в глобальном списке непрочитанных",
"form.category.label.title": "Название", "form.category.label.title": "Название",
@ -253,6 +254,16 @@
"form.integration.linkding_bookmark": "Помечать закладки как непрочитанное", "form.integration.linkding_bookmark": "Помечать закладки как непрочитанное",
"form.integration.linkding_endpoint": "Конечная точка Linkding API", "form.integration.linkding_endpoint": "Конечная точка Linkding API",
"form.integration.linkding_tags": "Теги Linkding", "form.integration.linkding_tags": "Теги Linkding",
"form.integration.linktaco_activate": "Сохранять статьи в LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Получить ваш персональный токен доступа на",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Теги (макс. 10, через запятую)",
"form.integration.linktaco_tags_hint": "Максимум 10 тегов, через запятую",
"form.integration.linktaco_visibility": "Видимость",
"form.integration.linktaco_visibility_public": "Публично",
"form.integration.linktaco_visibility_private": "Приватно",
"form.integration.linktaco_visibility_hint": "ПРИВАТНАЯ видимость требует платного аккаунта LinkTaco",
"form.integration.linkwarden_activate": "Сохранять статьи в Linkwarden", "form.integration.linkwarden_activate": "Сохранять статьи в Linkwarden",
"form.integration.linkwarden_api_key": "API-ключ Linkwarden", "form.integration.linkwarden_api_key": "API-ключ Linkwarden",
"form.integration.linkwarden_endpoint": "Базовый URL-адрес Linkwarden", "form.integration.linkwarden_endpoint": "Базовый URL-адрес Linkwarden",

View file

@ -160,6 +160,7 @@
"error.unlink_account_without_password": "Bir şifre belirlemelisiniz, aksi takdirde tekrar oturum açamazsınız.", "error.unlink_account_without_password": "Bir şifre belirlemelisiniz, aksi takdirde tekrar oturum açamazsınız.",
"error.user_already_exists": "Bu kullanıcı zaten mevcut.", "error.user_already_exists": "Bu kullanıcı zaten mevcut.",
"error.user_mandatory_fields": "Kullanıcı adı zorunlu.", "error.user_mandatory_fields": "Kullanıcı adı zorunlu.",
"error.linktaco_missing_required_fields": "LinkTaco API Token ve Organization Slug gereklidir",
"form.api_key.label.description": "API Anahtar Etiketi", "form.api_key.label.description": "API Anahtar Etiketi",
"form.category.hide_globally": "Genel okunmamış listesindeki girişleri gizle", "form.category.hide_globally": "Genel okunmamış listesindeki girişleri gizle",
"form.category.label.title": "Başlık", "form.category.label.title": "Başlık",
@ -250,6 +251,16 @@
"form.integration.linkding_bookmark": "Yer imini okunmadı olarak işaretle", "form.integration.linkding_bookmark": "Yer imini okunmadı olarak işaretle",
"form.integration.linkding_endpoint": "Linkding API Uç Noktası", "form.integration.linkding_endpoint": "Linkding API Uç Noktası",
"form.integration.linkding_tags": "Linkding Etiketleri", "form.integration.linkding_tags": "Linkding Etiketleri",
"form.integration.linktaco_activate": "Makaleleri LinkTaco'ya kaydet",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Kişisel erişim tokenınızı edinin",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Etiketler (maks 10, virgülle ayrılmış)",
"form.integration.linktaco_tags_hint": "Maksimum 10 etiket, virgülle ayrılmış",
"form.integration.linktaco_visibility": "Görünürlük",
"form.integration.linktaco_visibility_public": "Genel",
"form.integration.linktaco_visibility_private": "Özel",
"form.integration.linktaco_visibility_hint": "ÖZEL görünürlük ücretli bir LinkTaco hesabı gerektirir",
"form.integration.linkwarden_activate": "Makaleleri Linkwarden'e kaydet", "form.integration.linkwarden_activate": "Makaleleri Linkwarden'e kaydet",
"form.integration.linkwarden_api_key": "Linkwarden API Anahtarı", "form.integration.linkwarden_api_key": "Linkwarden API Anahtarı",
"form.integration.linkwarden_endpoint": "Linkwarden Temel URL'si", "form.integration.linkwarden_endpoint": "Linkwarden Temel URL'si",

View file

@ -162,7 +162,8 @@
"error.unable_to_update_user": "Не вдається оновити користувача.", "error.unable_to_update_user": "Не вдається оновити користувача.",
"error.unlink_account_without_password": "Ви маєте встановити пароль, щоб мати можливість увійти наступного разу", "error.unlink_account_without_password": "Ви маєте встановити пароль, щоб мати можливість увійти наступного разу",
"error.user_already_exists": "Такий користувач вже існує.", "error.user_already_exists": "Такий користувач вже існує.",
"error.user_mandatory_fields": "Ім’я користувача є обов’язковим.", "error.user_mandatory_fields": "Ім'я користувача є обов'язковим.",
"error.linktaco_missing_required_fields": "LinkTaco API Token і Organization Slug є обов'язковими",
"form.api_key.label.description": "Назва ключа API", "form.api_key.label.description": "Назва ключа API",
"form.category.hide_globally": "Приховати записи в глобальному списку непрочитаного", "form.category.hide_globally": "Приховати записи в глобальному списку непрочитаного",
"form.category.label.title": "Назва", "form.category.label.title": "Назва",
@ -253,6 +254,16 @@
"form.integration.linkding_bookmark": "Відмічати закладку як непрочитану", "form.integration.linkding_bookmark": "Відмічати закладку як непрочитану",
"form.integration.linkding_endpoint": "Linkding API Endpoint", "form.integration.linkding_endpoint": "Linkding API Endpoint",
"form.integration.linkding_tags": "Linkding Tags", "form.integration.linkding_tags": "Linkding Tags",
"form.integration.linktaco_activate": "Зберігати статті в LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "Отримайте ваш персональний токен доступу на",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "Теги (макс. 10, через кому)",
"form.integration.linktaco_tags_hint": "Максимум 10 тегів, через кому",
"form.integration.linktaco_visibility": "Видимість",
"form.integration.linktaco_visibility_public": "Публічно",
"form.integration.linktaco_visibility_private": "Приватно",
"form.integration.linktaco_visibility_hint": "ПРИВАТНА видимість потребує платного акаунта LinkTaco",
"form.integration.linkwarden_activate": "Зберігати статті до Linkwarden", "form.integration.linkwarden_activate": "Зберігати статті до Linkwarden",
"form.integration.linkwarden_api_key": "Ключ API Linkwarden", "form.integration.linkwarden_api_key": "Ключ API Linkwarden",
"form.integration.linkwarden_endpoint": "Базова URL-адреса Linkwarden", "form.integration.linkwarden_endpoint": "Базова URL-адреса Linkwarden",

View file

@ -157,6 +157,7 @@
"error.unlink_account_without_password": "您必须设置密码,否则您将无法再次登录。", "error.unlink_account_without_password": "您必须设置密码,否则您将无法再次登录。",
"error.user_already_exists": "此用户已存在。", "error.user_already_exists": "此用户已存在。",
"error.user_mandatory_fields": "必须填写用户名。", "error.user_mandatory_fields": "必须填写用户名。",
"error.linktaco_missing_required_fields": "LinkTaco API Token 和 Organization Slug 是必需的",
"form.api_key.label.description": "API 密钥标签", "form.api_key.label.description": "API 密钥标签",
"form.category.hide_globally": "在全局未读列表中隐藏条目", "form.category.hide_globally": "在全局未读列表中隐藏条目",
"form.category.label.title": "标题", "form.category.label.title": "标题",
@ -247,6 +248,16 @@
"form.integration.linkding_bookmark": "将书签标记为未读", "form.integration.linkding_bookmark": "将书签标记为未读",
"form.integration.linkding_endpoint": "Linkding API 端点", "form.integration.linkding_endpoint": "Linkding API 端点",
"form.integration.linkding_tags": "Linkding 标签", "form.integration.linkding_tags": "Linkding 标签",
"form.integration.linktaco_activate": "保存条目到 LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "在此获取您的个人访问令牌",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "标签最多10个逗号分隔",
"form.integration.linktaco_tags_hint": "最多10个标签逗号分隔",
"form.integration.linktaco_visibility": "可见性",
"form.integration.linktaco_visibility_public": "公开",
"form.integration.linktaco_visibility_private": "私人",
"form.integration.linktaco_visibility_hint": "私人可见性需要付费的 LinkTaco 帐户",
"form.integration.linkwarden_activate": "保存条目到 Linkwarden", "form.integration.linkwarden_activate": "保存条目到 Linkwarden",
"form.integration.linkwarden_api_key": "Linkwarden API 密钥", "form.integration.linkwarden_api_key": "Linkwarden API 密钥",
"form.integration.linkwarden_endpoint": "Linkwarden 基本 URL", "form.integration.linkwarden_endpoint": "Linkwarden 基本 URL",

View file

@ -157,6 +157,7 @@
"error.unlink_account_without_password": "您必須設定密碼,否則您將無法再次登入。", "error.unlink_account_without_password": "您必須設定密碼,否則您將無法再次登入。",
"error.user_already_exists": "使用者已存在", "error.user_already_exists": "使用者已存在",
"error.user_mandatory_fields": "必須填寫使用者名稱", "error.user_mandatory_fields": "必須填寫使用者名稱",
"error.linktaco_missing_required_fields": "LinkTaco API Token 和 Organization Slug 是必需的",
"form.api_key.label.description": "API 金鑰標籤", "form.api_key.label.description": "API 金鑰標籤",
"form.category.hide_globally": "在全域未讀列表中隱藏文章", "form.category.hide_globally": "在全域未讀列表中隱藏文章",
"form.category.label.title": "標題", "form.category.label.title": "標題",
@ -247,6 +248,16 @@
"form.integration.linkding_bookmark": "標記為未讀", "form.integration.linkding_bookmark": "標記為未讀",
"form.integration.linkding_endpoint": "Linkding API 端點", "form.integration.linkding_endpoint": "Linkding API 端點",
"form.integration.linkding_tags": "Linkding 標籤", "form.integration.linkding_tags": "Linkding 標籤",
"form.integration.linktaco_activate": "儲存文章到 LinkTaco",
"form.integration.linktaco_api_token": "LinkTaco API Token",
"form.integration.linktaco_api_token_hint": "在此取得您的個人存取權杖",
"form.integration.linktaco_org_slug": "Organization Slug",
"form.integration.linktaco_tags": "標籤最多10個逗號分隔",
"form.integration.linktaco_tags_hint": "最多10個標籤逗號分隔",
"form.integration.linktaco_visibility": "可見性",
"form.integration.linktaco_visibility_public": "公開",
"form.integration.linktaco_visibility_private": "私人",
"form.integration.linktaco_visibility_hint": "私人可見性需要付費的 LinkTaco 帳戶",
"form.integration.linkwarden_activate": "儲存文章到 Linkwarden", "form.integration.linkwarden_activate": "儲存文章到 Linkwarden",
"form.integration.linkwarden_api_key": "Linkwarden API 金鑰", "form.integration.linkwarden_api_key": "Linkwarden API 金鑰",
"form.integration.linkwarden_endpoint": "Linkwarden 基本 URL", "form.integration.linkwarden_endpoint": "Linkwarden 基本 URL",

View file

@ -59,6 +59,11 @@ type Integration struct {
LinkdingAPIKey string LinkdingAPIKey string
LinkdingTags string LinkdingTags string
LinkdingMarkAsUnread bool LinkdingMarkAsUnread bool
LinktacoEnabled bool
LinktacoAPIToken string
LinktacoOrgSlug string
LinktacoTags string
LinktacoVisibility string
LinkwardenEnabled bool LinkwardenEnabled bool
LinkwardenURL string LinkwardenURL string
LinkwardenAPIKey string LinkwardenAPIKey string

View file

@ -220,7 +220,12 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
rssbridge_token, rssbridge_token,
karakeep_enabled, karakeep_enabled,
karakeep_api_key, karakeep_api_key,
karakeep_url karakeep_url,
linktaco_enabled,
linktaco_api_token,
linktaco_org_slug,
linktaco_tags,
linktaco_visibility
FROM FROM
integrations integrations
WHERE WHERE
@ -340,6 +345,11 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
&integration.KarakeepEnabled, &integration.KarakeepEnabled,
&integration.KarakeepAPIKey, &integration.KarakeepAPIKey,
&integration.KarakeepURL, &integration.KarakeepURL,
&integration.LinktacoEnabled,
&integration.LinktacoAPIToken,
&integration.LinktacoOrgSlug,
&integration.LinktacoTags,
&integration.LinktacoVisibility,
) )
switch { switch {
case err == sql.ErrNoRows: case err == sql.ErrNoRows:
@ -467,9 +477,14 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
rssbridge_token=$108, rssbridge_token=$108,
karakeep_enabled=$109, karakeep_enabled=$109,
karakeep_api_key=$110, karakeep_api_key=$110,
karakeep_url=$111 karakeep_url=$111,
linktaco_enabled=$112,
linktaco_api_token=$113,
linktaco_org_slug=$114,
linktaco_tags=$115,
linktaco_visibility=$116
WHERE WHERE
user_id=$112 user_id=$117
` `
_, err := s.db.Exec( _, err := s.db.Exec(
query, query,
@ -584,6 +599,11 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
integration.KarakeepEnabled, integration.KarakeepEnabled,
integration.KarakeepAPIKey, integration.KarakeepAPIKey,
integration.KarakeepURL, integration.KarakeepURL,
integration.LinktacoEnabled,
integration.LinktacoAPIToken,
integration.LinktacoOrgSlug,
integration.LinktacoTags,
integration.LinktacoVisibility,
integration.UserID, integration.UserID,
) )
@ -614,6 +634,7 @@ func (s *Storage) HasSaveEntry(userID int64) (result bool) {
readwise_enabled='t' OR readwise_enabled='t' OR
linkace_enabled='t' OR linkace_enabled='t' OR
linkding_enabled='t' OR linkding_enabled='t' OR
linktaco_enabled='t' OR
linkwarden_enabled='t' OR linkwarden_enabled='t' OR
apprise_enabled='t' OR apprise_enabled='t' OR
shiori_enabled='t' OR shiori_enabled='t' OR

View file

@ -228,6 +228,37 @@
</div> </div>
</details> </details>
<details {{ if .form.LinktacoEnabled }}open{{ end }}>
<summary>LinkTaco</summary>
<div class="form-section">
<label>
<input type="checkbox" name="linktaco_enabled" value="1" {{ if .form.LinktacoEnabled }}checked{{ end }}> {{ t "form.integration.linktaco_activate" }}
</label>
<label for="form-linktaco-api-token">{{ t "form.integration.linktaco_api_token" }}</label>
<input type="password" name="linktaco_api_token" id="form-linktaco-api-token" value="{{ .form.LinktacoAPIToken }}" spellcheck="false">
<p class="hint">{{ t "form.integration.linktaco_api_token_hint" }} <a href="https://linktaco.com/oauth2/personal" target="_blank" rel="noopener noreferrer">https://linktaco.com/oauth2/personal</a></p>
<label for="form-linktaco-org-slug">{{ t "form.integration.linktaco_org_slug" }}</label>
<input type="text" name="linktaco_org_slug" id="form-linktaco-org-slug" value="{{ .form.LinktacoOrgSlug }}" placeholder="my-organization" spellcheck="false">
<label for="form-linktaco-tags">{{ t "form.integration.linktaco_tags" }}</label>
<input type="text" name="linktaco_tags" id="form-linktaco-tags" value="{{ .form.LinktacoTags }}" placeholder="miniflux, bookmarks" spellcheck="false">
<p class="hint">{{ t "form.integration.linktaco_tags_hint" }}</p>
<label for="form-linktaco-visibility">{{ t "form.integration.linktaco_visibility" }}</label>
<select name="linktaco_visibility" id="form-linktaco-visibility">
<option value="PUBLIC" {{ if eq .form.LinktacoVisibility "PUBLIC" }}selected{{ end }}>{{ t "form.integration.linktaco_visibility_public" }}</option>
<option value="PRIVATE" {{ if eq .form.LinktacoVisibility "PRIVATE" }}selected{{ end }}>{{ t "form.integration.linktaco_visibility_private" }}</option>
</select>
<p class="hint">{{ t "form.integration.linktaco_visibility_hint" }}</p>
<div class="buttons">
<button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>
</div>
</div>
</details>
<details {{ if .form.LinkwardenEnabled }}open{{ end }}> <details {{ if .form.LinkwardenEnabled }}open{{ end }}>
<summary>Linkwarden</summary> <summary>Linkwarden</summary>
<div class="form-section"> <div class="form-section">

View file

@ -62,6 +62,11 @@ type IntegrationForm struct {
LinkdingAPIKey string LinkdingAPIKey string
LinkdingTags string LinkdingTags string
LinkdingMarkAsUnread bool LinkdingMarkAsUnread bool
LinktacoEnabled bool
LinktacoAPIToken string
LinktacoOrgSlug string
LinktacoTags string
LinktacoVisibility string
LinkwardenEnabled bool LinkwardenEnabled bool
LinkwardenURL string LinkwardenURL string
LinkwardenAPIKey string LinkwardenAPIKey string
@ -175,6 +180,11 @@ func (i IntegrationForm) Merge(integration *model.Integration) {
integration.LinkdingAPIKey = i.LinkdingAPIKey integration.LinkdingAPIKey = i.LinkdingAPIKey
integration.LinkdingTags = i.LinkdingTags integration.LinkdingTags = i.LinkdingTags
integration.LinkdingMarkAsUnread = i.LinkdingMarkAsUnread integration.LinkdingMarkAsUnread = i.LinkdingMarkAsUnread
integration.LinktacoEnabled = i.LinktacoEnabled
integration.LinktacoAPIToken = i.LinktacoAPIToken
integration.LinktacoOrgSlug = i.LinktacoOrgSlug
integration.LinktacoTags = i.LinktacoTags
integration.LinktacoVisibility = i.LinktacoVisibility
integration.LinkwardenEnabled = i.LinkwardenEnabled integration.LinkwardenEnabled = i.LinkwardenEnabled
integration.LinkwardenURL = i.LinkwardenURL integration.LinkwardenURL = i.LinkwardenURL
integration.LinkwardenAPIKey = i.LinkwardenAPIKey integration.LinkwardenAPIKey = i.LinkwardenAPIKey
@ -290,6 +300,11 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm {
LinkdingAPIKey: r.FormValue("linkding_api_key"), LinkdingAPIKey: r.FormValue("linkding_api_key"),
LinkdingTags: r.FormValue("linkding_tags"), LinkdingTags: r.FormValue("linkding_tags"),
LinkdingMarkAsUnread: r.FormValue("linkding_mark_as_unread") == "1", LinkdingMarkAsUnread: r.FormValue("linkding_mark_as_unread") == "1",
LinktacoEnabled: r.FormValue("linktaco_enabled") == "1",
LinktacoAPIToken: r.FormValue("linktaco_api_token"),
LinktacoOrgSlug: r.FormValue("linktaco_org_slug"),
LinktacoTags: r.FormValue("linktaco_tags"),
LinktacoVisibility: r.FormValue("linktaco_visibility"),
LinkwardenEnabled: r.FormValue("linkwarden_enabled") == "1", LinkwardenEnabled: r.FormValue("linkwarden_enabled") == "1",
LinkwardenURL: r.FormValue("linkwarden_url"), LinkwardenURL: r.FormValue("linkwarden_url"),
LinkwardenAPIKey: r.FormValue("linkwarden_api_key"), LinkwardenAPIKey: r.FormValue("linkwarden_api_key"),

View file

@ -75,6 +75,11 @@ func (h *handler) showIntegrationPage(w http.ResponseWriter, r *http.Request) {
LinkdingAPIKey: integration.LinkdingAPIKey, LinkdingAPIKey: integration.LinkdingAPIKey,
LinkdingTags: integration.LinkdingTags, LinkdingTags: integration.LinkdingTags,
LinkdingMarkAsUnread: integration.LinkdingMarkAsUnread, LinkdingMarkAsUnread: integration.LinkdingMarkAsUnread,
LinktacoEnabled: integration.LinktacoEnabled,
LinktacoAPIToken: integration.LinktacoAPIToken,
LinktacoOrgSlug: integration.LinktacoOrgSlug,
LinktacoTags: integration.LinktacoTags,
LinktacoVisibility: integration.LinktacoVisibility,
LinkwardenEnabled: integration.LinkwardenEnabled, LinkwardenEnabled: integration.LinkwardenEnabled,
LinkwardenURL: integration.LinkwardenURL, LinkwardenURL: integration.LinkwardenURL,
LinkwardenAPIKey: integration.LinkwardenAPIKey, LinkwardenAPIKey: integration.LinkwardenAPIKey,

View file

@ -75,6 +75,17 @@ func (h *handler) updateIntegration(w http.ResponseWriter, r *http.Request) {
integration.WebhookSecret = "" integration.WebhookSecret = ""
} }
if integrationForm.LinktacoEnabled {
if integrationForm.LinktacoAPIToken == "" || integrationForm.LinktacoOrgSlug == "" {
sess.NewFlashErrorMessage(printer.Print("error.linktaco_missing_required_fields"))
html.Redirect(w, r, route.Path(h.router, "integrations"))
return
}
if integration.LinktacoVisibility == "" {
integration.LinktacoVisibility = "PUBLIC"
}
}
err = h.store.UpdateIntegration(integration) err = h.store.UpdateIntegration(integration)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)