mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-04-02 03:01:13 -04:00
feat: internationalize file manager, Vertex AI, and Copilot error messages via i18n
- Replace hardcoded error strings in `file_manager.go` with i18n translation keys - Add file manager, Vertex AI, and Copilot i18n keys to all 10 locale files - Internationalize Copilot plugin error messages and debug logs - Internationalize Vertex AI model fetching error messages - Fix JSON trailing comma syntax errors across all locale files - Normalize German locale JSON indentation from tabs to spaces - Use `AddSetupQuestionWithEnvName` for Bedrock AWS region setup
This commit is contained in:
@@ -55,7 +55,7 @@ func NewClient() (ret *BedrockClient) {
|
||||
ret.PluginBase = plugins.NewVendorPluginBase(vendorName, func() error {
|
||||
return fmt.Errorf(i18n.T("bedrock_unable_load_aws_config"), err)
|
||||
})
|
||||
ret.bedrockRegion = ret.PluginBase.AddSetupQuestion(i18n.T("bedrock_aws_region_label"), true)
|
||||
ret.bedrockRegion = ret.PluginBase.AddSetupQuestionWithEnvName("AWS Region", true, i18n.T("bedrock_aws_region_label"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func NewClient() (ret *BedrockClient) {
|
||||
ret.runtimeClient = runtimeClient
|
||||
ret.controlPlaneClient = controlPlaneClient
|
||||
|
||||
ret.bedrockRegion = ret.PluginBase.AddSetupQuestion(i18n.T("bedrock_aws_region_label"), true)
|
||||
ret.bedrockRegion = ret.PluginBase.AddSetupQuestionWithEnvName("AWS Region", true, i18n.T("bedrock_aws_region_label"))
|
||||
|
||||
if cfg.Region != "" {
|
||||
ret.bedrockRegion.Value = cfg.Region
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"github.com/danielmiessler/fabric/internal/chat"
|
||||
"github.com/danielmiessler/fabric/internal/domain"
|
||||
"github.com/danielmiessler/fabric/internal/i18n"
|
||||
debuglog "github.com/danielmiessler/fabric/internal/log"
|
||||
"github.com/danielmiessler/fabric/internal/plugins"
|
||||
"golang.org/x/oauth2"
|
||||
@@ -106,7 +107,7 @@ type Client struct {
|
||||
// configure initializes the client with OAuth2 configuration.
|
||||
func (c *Client) configure() error {
|
||||
if c.TenantID.Value == "" || c.ClientID.Value == "" {
|
||||
return fmt.Errorf("tenant ID and client ID are required")
|
||||
return fmt.Errorf("%s", i18n.T("copilot_tenant_client_id_required"))
|
||||
}
|
||||
|
||||
// Build OAuth2 configuration
|
||||
@@ -168,7 +169,7 @@ func (c *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o
|
||||
// Create a conversation
|
||||
conversationID, err := c.createConversation(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create conversation: %w", err)
|
||||
return "", fmt.Errorf(i18n.T("copilot_failed_create_conversation"), err)
|
||||
}
|
||||
|
||||
// Build the message content from chat messages
|
||||
@@ -177,7 +178,7 @@ func (c *Client) Send(ctx context.Context, msgs []*chat.ChatCompletionMessage, o
|
||||
// Send the chat message
|
||||
response, err := c.sendChatMessage(ctx, conversationID, messageText)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to send message: %w", err)
|
||||
return "", fmt.Errorf(i18n.T("copilot_failed_send_message"), err)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
@@ -192,7 +193,7 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha
|
||||
// Create a conversation
|
||||
conversationID, err := c.createConversation(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create conversation: %w", err)
|
||||
return fmt.Errorf(i18n.T("copilot_failed_create_conversation"), err)
|
||||
}
|
||||
|
||||
// Build the message content from chat messages
|
||||
@@ -200,7 +201,7 @@ func (c *Client) SendStream(msgs []*chat.ChatCompletionMessage, opts *domain.Cha
|
||||
|
||||
// Send the streaming chat message
|
||||
if err := c.sendChatMessageStream(ctx, conversationID, messageText, channel); err != nil {
|
||||
return fmt.Errorf("failed to stream message: %w", err)
|
||||
return fmt.Errorf(i18n.T("copilot_failed_stream_message"), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -253,7 +254,7 @@ func (c *Client) createConversation(ctx context.Context) (string, error) {
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return "", fmt.Errorf("failed to create conversation: %s - %s", resp.Status, string(body))
|
||||
return "", fmt.Errorf(i18n.T("copilot_error_create_conversation"), resp.Status, string(body))
|
||||
}
|
||||
|
||||
var result conversationResponse
|
||||
@@ -261,7 +262,7 @@ func (c *Client) createConversation(ctx context.Context) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
debuglog.Debug(debuglog.Detailed, "Created Copilot conversation: %s\n", result.ID)
|
||||
debuglog.Debug(debuglog.Detailed, i18n.T("copilot_debug_created_conversation")+"\n", result.ID)
|
||||
return result.ID, nil
|
||||
}
|
||||
|
||||
@@ -299,7 +300,7 @@ func (c *Client) sendChatMessage(ctx context.Context, conversationID, messageTex
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return "", fmt.Errorf("chat request failed: %s - %s", resp.Status, string(body))
|
||||
return "", fmt.Errorf(i18n.T("copilot_error_chat_request"), resp.Status, string(body))
|
||||
}
|
||||
|
||||
var result conversationResponse
|
||||
@@ -346,7 +347,7 @@ func (c *Client) sendChatMessageStream(ctx context.Context, conversationID, mess
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("stream request failed: %s - %s", resp.Status, string(body))
|
||||
return fmt.Errorf(i18n.T("copilot_error_stream_request"), resp.Status, string(body))
|
||||
}
|
||||
|
||||
// Parse SSE stream
|
||||
@@ -373,7 +374,7 @@ func (c *Client) parseSSEStream(reader io.Reader, channel chan domain.StreamUpda
|
||||
|
||||
var event conversationResponse
|
||||
if err := json.Unmarshal([]byte(jsonData), &event); err != nil {
|
||||
debuglog.Debug(debuglog.Detailed, "Failed to parse SSE event: %v\n", err)
|
||||
debuglog.Debug(debuglog.Detailed, i18n.T("copilot_debug_failed_parse_sse_event")+"\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -394,7 +395,7 @@ func (c *Client) parseSSEStream(reader io.Reader, channel chan domain.StreamUpda
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return fmt.Errorf("error reading stream: %w", err)
|
||||
return fmt.Errorf(i18n.T("copilot_error_reading_stream"), err)
|
||||
}
|
||||
|
||||
channel <- domain.StreamUpdate{Type: domain.StreamTypeContent, Content: "\n"}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/danielmiessler/fabric/internal/i18n"
|
||||
debuglog "github.com/danielmiessler/fabric/internal/log"
|
||||
)
|
||||
|
||||
@@ -40,7 +41,7 @@ type publisherModel struct {
|
||||
func fetchModelsPage(ctx context.Context, httpClient *http.Client, url, projectID, publisher string) (*publisherModelsResponse, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||
return nil, fmt.Errorf(i18n.T("vertexai_error_create_request"), err)
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", "application/json")
|
||||
@@ -49,28 +50,28 @@ func fetchModelsPage(ctx context.Context, httpClient *http.Client, url, projectI
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("request failed: %w", err)
|
||||
return nil, fmt.Errorf(i18n.T("vertexai_error_request_failed"), err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(io.LimitReader(resp.Body, errorResponseLimit))
|
||||
debuglog.Debug(debuglog.Basic, "API error for %s: status %d, url: %s, body: %s\n", publisher, resp.StatusCode, url, string(bodyBytes))
|
||||
return nil, fmt.Errorf("API returned status %d: %s", resp.StatusCode, string(bodyBytes))
|
||||
return nil, fmt.Errorf(i18n.T("vertexai_error_api_status"), resp.StatusCode, string(bodyBytes))
|
||||
}
|
||||
|
||||
bodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize+1))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||
return nil, fmt.Errorf(i18n.T("vertexai_error_read_response"), err)
|
||||
}
|
||||
|
||||
if len(bodyBytes) > maxResponseSize {
|
||||
return nil, fmt.Errorf("response too large (>%d bytes)", maxResponseSize)
|
||||
return nil, fmt.Errorf(i18n.T("vertexai_error_response_too_large"), maxResponseSize)
|
||||
}
|
||||
|
||||
var response publisherModelsResponse
|
||||
if err := json.Unmarshal(bodyBytes, &response); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse response: %w", err)
|
||||
return nil, fmt.Errorf(i18n.T("vertexai_error_parse_response"), err)
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
|
||||
Reference in New Issue
Block a user