@braze/sanity-plugin-ai-translation 0.1.7 → 0.1.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/hooks/useTranslationContext/TranslationContext.ts","../src/hooks/useTranslationContext/useTranslationContext.ts","../src/consts.ts","../src/utils/undraftId.ts","../src/hooks/useTranslationMetadata/useTranslationMetadata.ts","../src/utils/devLog.ts","../src/utils/processFeedback.ts","../src/components/ProgressPanel.tsx","../src/components/SuggestionReviewList.tsx","../src/components/GiveFeedbackDialog.tsx","../src/hooks/useTranslationContext/translationReducer.ts","../src/hooks/useTranslationContext/TranslationContextProvider.tsx","../src/GiveTranslationFeedbackAction.tsx","../src/schemas/translationGlossaryTerm.schema.ts","../src/schemas/translationHistory.schema.ts","../src/schemas/translationSettings.schema.ts","../src/utils/fetchTranslationPrompts.ts","../src/utils/findKeyValues/findKeyValues.ts","../src/utils/localizeReferences.ts","../src/utils/Semaphore.ts","../src/utils/setupTranslationJobStatuses.ts","../src/utils/getExistingTranslationId.ts","../src/utils/determineTranslationTarget.ts","../src/utils/getTranslationMetadata.ts","../src/utils/setJobStatus.ts","../src/utils/translateDocumentInPlace.ts","../src/utils/assembleLanguageSpecs.ts","../src/utils/translateEntireDocument.ts","../src/utils/updateTranslationMetadata.ts","../src/utils/translateDocument.ts","../src/utils/translateDocumentSet.ts","../src/components/ActionButtonBar.tsx","../src/components/LanguageCheckbox.tsx","../src/components/LanguageSelectionPanel.tsx","../src/utils/assembleReferences.ts","../src/components/ReferenceConfigPanel.tsx","../src/components/WriteSettingsPanel.tsx","../src/components/TranslationConfigPanel.tsx","../src/components/TranslationStatusPanel.tsx","../src/components/TranslationDialog.tsx","../src/TranslateAction.tsx","../src/index.ts"],"sourcesContent":["import { createContext } from 'react'\nimport type { TranslationJob, TranslationContext as TTranslationContext } from '../../types'\n\nexport const TranslationContext = createContext<TTranslationContext>({\n document: null,\n config: null,\n overallStatus: 'idle',\n selectedTargetLanguages: [],\n translationJobs: new Map<string, TranslationJob>(),\n shouldTranslateDiffs: false,\n shouldOverwriteFreshTranslations: false,\n shouldTranslateReferences: false,\n maxReferenceDepth: 1,\n references: [],\n translationMetadata: null,\n dispatch: () => {},\n})\n","import { useContext } from 'react'\nimport type { TranslationContext as TTranslationContext } from '../../types'\nimport { TranslationContext } from './TranslationContext'\n\ninterface ValidatedTranslationContext extends TTranslationContext {\n document: NonNullable<TTranslationContext['document']>\n config: NonNullable<TTranslationContext['config']>\n}\n\nexport const useTranslationContext = (): ValidatedTranslationContext => {\n const context = useContext(TranslationContext)\n\n if (!context.document || !context.config) {\n throw new Error(\n 'useTranslationContext must be used within a TranslationContextProvider with document and config props',\n )\n }\n\n return context as ValidatedTranslationContext\n}\n","export const TRANSLATION_METADATA_TYPE = 'translation.metadata'\nexport const UPDATE_EXISTING_TRANSLATION_PROMPT =\n '***IMPORTANT:** This document has an existing, but out-of-date translation. Please review the existing translation before processing and change as little as possible. Existing translation: $extantTranslation'\n","// Remove `drafts.` from a string\nexport const undraftId = (id: string) => id.replace(/^drafts\\./, '')\n\nexport const draftId = (id: string) => `drafts.${undraftId(id)}`\n","import { useEffect } from 'react'\nimport { useListeningQuery } from 'sanity-plugin-utils'\nimport { TRANSLATION_METADATA_TYPE } from '../../consts'\nimport type { TranslationMetadataDocument } from '../../types'\nimport { undraftId } from '../../utils/undraftId'\nimport { useTranslationContext } from '../useTranslationContext'\n\nconst TRANSLATION_METADATA_QUERY = '*[_type == $translationMetadataType && references($documentId)][0]'\n\ninterface UseTranslationMetadataProps {\n documentId: string\n}\n\nexport const useTranslationMetadata = ({ documentId }: UseTranslationMetadataProps) => {\n const { dispatch } = useTranslationContext()\n\n const { data, loading, error } = useListeningQuery<TranslationMetadataDocument | null>(TRANSLATION_METADATA_QUERY, {\n params: {\n documentId: undraftId(documentId),\n translationMetadataType: TRANSLATION_METADATA_TYPE,\n },\n initialValue: null,\n })\n\n useEffect(() => {\n if (loading) {\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'fetching_metadata' })\n return\n }\n\n if (error) {\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'error' })\n return\n }\n\n if (data) {\n dispatch({ type: 'SET_TRANSLATION_METADATA', payload: data as TranslationMetadataDocument })\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'idle' })\n return\n }\n\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'idle' })\n }, [data, loading, error, dispatch])\n\n return {\n data,\n loading,\n error,\n }\n}\n","/**\n * Development logging utility for AI Translation plugin troubleshooting\n * Only logs when SANITY_STUDIO_AI_TRANSLATION_PLUGIN_LOGGING environment variable is \"true\"\n */\n\nconst isLoggingEnabled = (): boolean => {\n return process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLATION_PLUGIN_LOGGING === 'true'\n}\n\nexport interface DevLogContext {\n component?: string\n action?: string\n documentId?: string\n language?: string\n jobId?: string\n // biome-ignore lint/suspicious/noExplicitAny: not worth the effort\n [key: string]: any\n}\n\nexport const devLog = {\n info: (message: string, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.info('[AI Translation]', message, context ? JSON.stringify(context, null, 2) : '')\n },\n\n warn: (message: string, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.warn('[AI Translation]', message, context ? JSON.stringify(context, null, 2) : '')\n },\n\n error: (message: string, error?: Error | unknown, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.error('[AI Translation]', message, error, context ? JSON.stringify(context, null, 2) : '')\n },\n\n debug: (message: string, data?: unknown, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.debug('[AI Translation]', message, data, context ? JSON.stringify(context, null, 2) : '')\n },\n\n group: (label: string, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.group(`[AI Translation] ${label}`, context ? JSON.stringify(context, null, 2) : '')\n },\n\n groupEnd: () => {\n if (!isLoggingEnabled()) return\n console.groupEnd()\n },\n\n time: (label: string) => {\n if (!isLoggingEnabled()) return\n console.time(`[AI Translation] ${label}`)\n },\n\n timeEnd: (label: string) => {\n if (!isLoggingEnabled()) return\n console.timeEnd(`[AI Translation] ${label}`)\n },\n}\n","import type { SanityClient } from 'sanity'\nimport type { FeedbackSuggestion } from '../types'\nimport { devLog } from './devLog'\n\ninterface ProcessFeedbackOptions {\n client: SanityClient\n schemaId: string\n sourceLanguage: string\n targetLanguage: string\n userFeedback?: string\n shouldIncludeEdits: boolean\n sourceSnapshot?: string\n targetSnapshot?: string\n currentDocument?: Record<string, unknown>\n onProgress?: (state: { stage: 'analyzing' | 'applying'; message: string }) => void\n}\n\ninterface AnalyzeFeedbackOptions {\n client: SanityClient\n schemaId: string\n sourceLanguage: string\n targetLanguage: string\n userFeedback?: string\n shouldIncludeEdits: boolean\n sourceSnapshot?: string\n targetSnapshot?: string\n currentDocument?: Record<string, unknown>\n onProgress?: (state: { stage: 'analyzing'; message: string }) => void\n}\n\ninterface ApplySuggestionsOptions {\n client: SanityClient\n schemaId: string\n sourceLanguage: string\n targetLanguage: string\n suggestions: FeedbackSuggestion[]\n onProgress?: (state: { stage: 'applying'; message: string }) => void\n}\n\ninterface FeedbackAnalysis {\n globalPromptUpdates?: string\n localePromptUpdates?: string\n protectedPhrasesToAdd?: string[]\n glossaryTermsToAdd?: Array<{\n sourceLocale: string\n targetLocale: string\n sourceValue: string\n targetValue: string\n }>\n reasoning: string\n}\n\n/**\n * Analyzes user feedback and inferred edits to generate improvement suggestions.\n *\n * This function:\n * 1. Analyzes explicit user feedback and/or edits made to translated content\n * 2. Uses AI to infer improvements to translation settings\n * 3. Returns a list of suggestions for the user to review\n *\n * @param options - Configuration for feedback analysis\n * @returns Promise that resolves with array of feedback suggestions\n */\nexport async function analyzeFeedback({\n client,\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n onProgress,\n}: AnalyzeFeedbackOptions): Promise<FeedbackSuggestion[]> {\n devLog.info('Starting feedback analysis', {\n sourceLanguage,\n targetLanguage,\n hasUserFeedback: !!userFeedback,\n shouldIncludeEdits,\n })\n\n onProgress?.({ stage: 'analyzing', message: 'Analyzing feedback and edits...' })\n\n const analysisPrompt = buildAnalysisPrompt({\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n })\n\n const analysis = await analyzeWithAI(client, analysisPrompt)\n devLog.info('AI analysis complete', { analysis })\n\n const suggestions = convertAnalysisToSuggestions(analysis)\n devLog.info('Generated suggestions', { count: suggestions.length })\n\n return suggestions\n}\n\n/**\n * Applies approved feedback suggestions to translation settings and glossary.\n *\n * @param options - Configuration for applying suggestions\n * @returns Promise that resolves when suggestions have been applied\n */\nexport async function applySuggestions({\n client,\n schemaId,\n sourceLanguage,\n targetLanguage,\n suggestions,\n onProgress,\n}: ApplySuggestionsOptions): Promise<void> {\n devLog.info('Applying suggestions', {\n sourceLanguage,\n targetLanguage,\n targetLanguageType: typeof targetLanguage,\n targetLanguageValue: targetLanguage,\n count: suggestions.filter((s) => s.approved).length,\n })\n\n if (!targetLanguage) {\n devLog.error('targetLanguage is undefined in applySuggestions!', {\n sourceLanguage,\n targetLanguage,\n suggestionsCount: suggestions.length,\n })\n throw new Error('targetLanguage is required but was undefined')\n }\n\n const approvedSuggestions = suggestions.filter((s) => s.approved)\n\n if (approvedSuggestions.length === 0) {\n devLog.info('No approved suggestions to apply')\n return\n }\n\n onProgress?.({ stage: 'applying', message: 'Applying updates to translation settings...' })\n\n await applyImprovementsFromSuggestions(client, schemaId, targetLanguage, approvedSuggestions, onProgress)\n\n devLog.info('Suggestions applied successfully')\n}\n\n/**\n * Processes user feedback and inferred edits to improve translation prompts and glossary.\n * This is a convenience function that combines analysis and application in one step.\n *\n * @deprecated Use analyzeFeedback and applySuggestions separately for better UX\n * @param options - Configuration for feedback processing\n * @returns Promise that resolves when feedback has been processed\n */\nexport async function processFeedback({\n client,\n schemaId,\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n onProgress,\n}: ProcessFeedbackOptions): Promise<void> {\n const suggestions = await analyzeFeedback({\n client,\n schemaId,\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n onProgress: onProgress ? (state) => onProgress({ ...state, stage: 'analyzing' }) : undefined,\n })\n\n await applySuggestions({\n client,\n schemaId,\n sourceLanguage,\n targetLanguage,\n suggestions,\n onProgress: onProgress ? (state) => onProgress({ ...state, stage: 'applying' }) : undefined,\n })\n}\n\n/**\n * Builds the prompt for AI analysis of user feedback and edits.\n */\nfunction buildAnalysisPrompt({\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n}: {\n sourceLanguage: string\n targetLanguage: string\n userFeedback?: string\n shouldIncludeEdits: boolean\n sourceSnapshot?: string\n targetSnapshot?: string\n currentDocument?: Record<string, unknown>\n}): string {\n const parts: string[] = [\n 'You are analyzing feedback about AI translation quality to improve future translations.',\n `Source language: ${sourceLanguage}`,\n `Target language: ${targetLanguage}`,\n '',\n 'Your task is to analyze the feedback and infer specific improvements to:',\n '1. Global translation prompt (general guidance for all translations)',\n '2. Locale-specific prompt (guidance specific to this target language)',\n '3. Protected phrases (terms that should never be translated)',\n '4. Glossary terms (specific term-to-term translation mappings)',\n '',\n ]\n\n if (userFeedback) {\n parts.push('USER FEEDBACK:', userFeedback, '')\n }\n\n if (shouldIncludeEdits && sourceSnapshot && targetSnapshot && currentDocument) {\n parts.push(\n 'EDIT ANALYSIS:',\n 'Compare the original translation with the edited version to understand what the user changed.',\n '',\n 'Original source document:',\n sourceSnapshot,\n '',\n 'Original AI translation:',\n targetSnapshot,\n '',\n 'Current edited document:',\n JSON.stringify(currentDocument, null, 2),\n '',\n )\n }\n\n parts.push(\n 'INSTRUCTIONS:',\n 'Analyze the feedback and/or edits to identify patterns and improvements.',\n '',\n 'For edits, look for:',\n '- Terminology changes that suggest glossary additions',\n '- Phrases that were protected/unprotected incorrectly',\n '- Style, tone, or formatting issues that suggest prompt improvements',\n '- Consistent patterns across multiple changes',\n '',\n 'IMPORTANT RULES:',\n '1. DO NOT create redundant updates. Choose ONE mechanism for each issue:',\n ' - Protected phrases = terms that should NEVER be translated (language-agnostic)',\n ' - Glossary terms = specific translation mappings (e.g., \"chat\" → \"cat\" in French)',\n ' - Locale prompts = guidance specific to this source→target language pair',\n ' - Global prompts = guidance that applies to ALL translations',\n '',\n '2. Be locale-specific:',\n ` - This feedback is specifically about ${sourceLanguage} → ${targetLanguage} translation`,\n ' - DO NOT assume rules apply to other language pairs unless explicitly stated',\n ' - Prefer locale-specific prompts over global prompts unless universally applicable',\n '',\n '3. Protected phrases vs. Locale prompts:',\n ' - Use protected phrases ONLY for brand names, product names, proper nouns, technical terms that should NEVER be translated in ANY language',\n ' - Use locale prompts for language-pair-specific guidance (e.g., \"Keep technical terms in English when translating to German\")',\n ' - NEVER mention specific terms in both protected phrases AND prompts',\n '',\n '4. Glossary vs. Protected phrases:',\n ' - Glossary = \"Always translate X as Y\" (provides the correct translation)',\n ' - Protected = \"Never translate X\" (keeps it as-is)',\n ' - CRITICAL: If sourceValue === targetValue, use PROTECTED PHRASES, NOT glossary',\n ' - Only use glossary when the term actually changes between languages',\n ' - Use protected when the term should remain unchanged across all languages',\n '',\n 'Output a JSON object with this structure:',\n '{',\n ' \"globalPromptUpdates\": \"string | null - ONLY if this applies to ALL language pairs\",',\n ` \"localePromptUpdates\": \"string | null - ONLY if this is specific to ${sourceLanguage}→${targetLanguage}\",`,\n ' \"protectedPhrasesToAdd\": [\"ONLY brand names, products, proper nouns that should NEVER translate\"],',\n ' \"glossaryTermsToAdd\": [{\"sourceLocale\": \"sourceLocale\",\"sourceValue\": \"term\", \"targetLocale\": \"targetLocale\", \"targetValue\": \"translation\"} - ONLY specific term mappings],',\n ' \"reasoning\": \"string - Explain your analysis and which mechanism you chose for each issue\"',\n '}',\n '',\n 'Be conservative: only suggest changes when there is clear evidence.',\n 'If in doubt, prefer locale-specific updates over global updates.',\n 'Avoid redundancy - if you add a protected phrase, do NOT mention it in prompts.',\n )\n\n return parts.join('\\n')\n}\n\n/**\n * Converts AI analysis results into user-reviewable suggestions.\n */\nfunction convertAnalysisToSuggestions(analysis: FeedbackAnalysis): FeedbackSuggestion[] {\n const suggestions: FeedbackSuggestion[] = []\n\n if (analysis.globalPromptUpdates) {\n suggestions.push({\n id: crypto.randomUUID(),\n type: 'globalPrompt',\n description: analysis.globalPromptUpdates,\n approved: true,\n })\n }\n\n if (analysis.localePromptUpdates) {\n suggestions.push({\n id: crypto.randomUUID(),\n type: 'localePrompt',\n description: analysis.localePromptUpdates,\n approved: true,\n })\n }\n\n if (analysis.protectedPhrasesToAdd) {\n for (const phrase of analysis.protectedPhrasesToAdd) {\n suggestions.push({\n id: crypto.randomUUID(),\n type: 'protectedPhrase',\n description: phrase,\n approved: true,\n })\n }\n }\n\n if (analysis.glossaryTermsToAdd) {\n for (const term of analysis.glossaryTermsToAdd) {\n suggestions.push({\n id: crypto.randomUUID(),\n type: 'glossaryTerm',\n description: `${term.sourceValue} → ${term.targetValue}`,\n approved: true,\n sourceLocale: term.sourceLocale,\n sourceValue: term.sourceValue,\n targetLocale: term.targetLocale,\n targetValue: term.targetValue,\n })\n }\n }\n\n return suggestions\n}\n\n/**\n * Uses Sanity AI Agent to analyze feedback and infer improvements.\n */\nasync function analyzeWithAI(client: SanityClient, prompt: string): Promise<FeedbackAnalysis> {\n try {\n const response = await client.agent.action.prompt({\n instruction: prompt,\n format: 'json',\n })\n\n devLog.debug('AI response received', { responseType: typeof response })\n\n const responseText =\n typeof response === 'string'\n ? response\n : response && typeof response === 'object'\n ? JSON.stringify(response)\n : (() => {\n throw new Error(`Unexpected response type: ${typeof response}`)\n })()\n\n return parseAIResponse(responseText)\n } catch (error) {\n devLog.error('Error during AI analysis', { error })\n throw new Error(`Failed to analyze feedback: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n}\n\n/**\n * Parses the AI response text to extract the feedback analysis.\n */\nfunction parseAIResponse(responseText: string): FeedbackAnalysis {\n try {\n let parsed: unknown\n try {\n parsed = JSON.parse(responseText)\n } catch {\n const jsonMatch = responseText.match(/\\{[\\s\\S]*\\}/)\n if (!jsonMatch) throw new Error('No JSON found in AI response')\n parsed = JSON.parse(jsonMatch[0])\n }\n\n if (!parsed || typeof parsed !== 'object') {\n throw new Error('Response is not a valid object')\n }\n\n const analysis = parsed as FeedbackAnalysis\n if (typeof analysis.reasoning !== 'string') {\n throw new Error('Invalid response structure: missing reasoning')\n }\n\n return {\n globalPromptUpdates: analysis.globalPromptUpdates || undefined,\n localePromptUpdates: analysis.localePromptUpdates || undefined,\n protectedPhrasesToAdd: Array.isArray(analysis.protectedPhrasesToAdd) ? analysis.protectedPhrasesToAdd : [],\n glossaryTermsToAdd: Array.isArray(analysis.glossaryTermsToAdd) ? analysis.glossaryTermsToAdd : [],\n reasoning: analysis.reasoning,\n }\n } catch (error) {\n devLog.error('Error parsing AI response', { error, responseText })\n throw new Error('Failed to parse AI response as JSON')\n }\n}\n\n/**\n * Applies the inferred improvements from suggestions to translation settings and glossary.\n */\nasync function applyImprovementsFromSuggestions(\n client: SanityClient,\n schemaId: string,\n targetLanguage: string,\n suggestions: FeedbackSuggestion[],\n onProgress?: (state: { stage: 'applying'; message: string }) => void,\n): Promise<void> {\n devLog.info('Applying improvements from suggestions', { count: suggestions.length })\n\n const settingsId = 'translation-settings'\n\n // Create the document if it doesn't exist\n const settings = await client.fetch('*[_id == $id][0]', { id: settingsId })\n if (!settings) {\n await client.createIfNotExists({\n _id: settingsId,\n _type: 'translationSettings',\n })\n }\n\n const updates: Array<Promise<unknown>> = []\n\n // Group suggestions by type and filter out empty values\n const globalPrompts = suggestions.filter((s) => s.type === 'globalPrompt' && s.description.trim())\n const localePrompts = suggestions.filter((s) => s.type === 'localePrompt' && s.description.trim())\n const protectedPhrases = suggestions.filter((s) => s.type === 'protectedPhrase' && s.description.trim())\n const glossaryTerms = suggestions.filter(\n (s) =>\n s.type === 'glossaryTerm' &&\n s.sourceLocale?.trim() &&\n s.sourceValue?.trim() &&\n s.targetLocale?.trim() &&\n s.targetValue?.trim(),\n )\n\n devLog.info('Filtered suggestions by type', {\n globalPrompts: globalPrompts.length,\n localePrompts: localePrompts.length,\n protectedPhrases: protectedPhrases.length,\n glossaryTerms: glossaryTerms.length,\n })\n\n // Apply both global and locale prompts in a single transform call\n if (globalPrompts.length > 0 || localePrompts.length > 0) {\n onProgress?.({\n stage: 'applying',\n message:\n globalPrompts.length > 0 && localePrompts.length > 0\n ? 'Updating global and locale translation prompts...'\n : globalPrompts.length > 0\n ? 'Updating global translation prompt...'\n : `Updating ${targetLanguage} translation prompt...`,\n })\n\n updates.push(updatePromptsWithTransform(client, schemaId, settingsId, targetLanguage, globalPrompts, localePrompts))\n }\n\n // Apply protected phrases\n if (protectedPhrases.length > 0) {\n onProgress?.({ stage: 'applying', message: 'Adding protected phrases...' })\n const phrases = protectedPhrases.map((s) => s.description)\n devLog.debug('Applying protected phrases', { phrases })\n updates.push(addProtectedPhrases(client, settingsId, phrases))\n }\n\n // Apply glossary terms\n if (glossaryTerms.length > 0) {\n onProgress?.({ stage: 'applying', message: 'Adding glossary terms...' })\n const terms = glossaryTerms.map((s) => ({\n // biome-ignore-start lint/style/noNonNullAssertion: safely handled\n sourceLocale: s.sourceLocale!,\n sourceValue: s.sourceValue!,\n targetLocale: s.targetLocale!,\n targetValue: s.targetValue!,\n // biome-ignore-end lint/style/noNonNullAssertion: safely handled\n }))\n devLog.debug('Applying glossary terms', { terms })\n updates.push(addGlossaryTerms(client, terms))\n }\n\n if (updates.length === 0) {\n devLog.warn('No valid updates to apply - all suggestions may have been empty')\n }\n\n await Promise.all(updates)\n devLog.info('All improvements applied successfully')\n}\n\n/**\n * Updates both global and locale prompts using a single transform action.\n * This uses Sanity Agent transform with multiple targets for efficient updates.\n */\nasync function updatePromptsWithTransform(\n client: SanityClient,\n schemaId: string,\n settingsId: string,\n targetLanguage: string,\n globalPrompts: FeedbackSuggestion[],\n localePrompts: FeedbackSuggestion[],\n): Promise<void> {\n devLog.info('Updating prompts with transform action', {\n settingsId,\n targetLanguage,\n targetLanguageType: typeof targetLanguage,\n targetLanguageValue: targetLanguage,\n hasGlobalUpdates: globalPrompts.length > 0,\n hasLocaleUpdates: localePrompts.length > 0,\n })\n\n if (!targetLanguage) {\n devLog.error('targetLanguage is undefined or empty!', {\n targetLanguage,\n globalPrompts: globalPrompts.length,\n localePrompts: localePrompts.length,\n })\n throw new Error('targetLanguage is required but was undefined')\n }\n\n // Build targets array for transform action\n const targets: Array<{\n path: string | string[]\n instruction: string\n }> = []\n\n // Add global prompt target if we have updates\n if (globalPrompts.length > 0) {\n const combinedGlobalUpdate = globalPrompts.map((s) => s.description).join('\\n\\n')\n targets.push({\n path: 'globalPrompt',\n instruction: `You are updating a translation prompt document that contains rules and guidance for future AI translations.\n\nIMPORTANT: The text below is NEW GUIDANCE that should be INCORPORATED INTO the existing prompt as additional rules/instructions for future translations. DO NOT apply or execute these rules on the prompt text itself.\n\nYour task: Merge the new guidance below into the existing prompt text. Treat the new guidance as rules that will guide future translations, not as transformations to apply to the current text.\n\nIntegration guidelines:\n- Add the new guidance as additional instructions/rules in the prompt\n- If it conflicts with existing guidance, update or replace the conflicting parts\n- If it's already covered, don't add redundant text\n- Maintain clear structure and consistent tone\n- Preserve all existing guidance that is still relevant\n- Keep the prompt written as instructions for a translator (e.g., \"When translating, you should...\" not \"The translation has been...\")\n\nNew guidance to incorporate:\n\n\\`\\`\\`\n${combinedGlobalUpdate}\n\\`\\`\\``,\n })\n devLog.debug('Added global prompt target', { combinedUpdate: combinedGlobalUpdate })\n }\n\n // Add locale prompt target if we have updates\n if (localePrompts.length > 0) {\n const combinedLocaleUpdate = localePrompts.map((s) => s.description).join('\\n\\n')\n\n // Check if locale prompt exists, if not create it first\n const existingLocalePrompts = await client.fetch<Array<{ _key: string; value: string }>>(\n '*[_id == $settingsId][0].localePrompts',\n { settingsId },\n )\n\n const hasExistingLocalePrompt = existingLocalePrompts?.some((lp) => lp._key === targetLanguage)\n devLog.debug('Checking existing locale prompt', {\n targetLanguage,\n hasExistingLocalePrompt,\n existingCount: existingLocalePrompts?.length || 0,\n })\n\n if (!hasExistingLocalePrompt) {\n // Create the locale prompt entry first\n devLog.info('Creating new locale prompt entry', { targetLanguage })\n await client\n .patch(settingsId)\n .setIfMissing({ localePrompts: [] })\n .append('localePrompts', [\n {\n _type: 'internationalizedArrayTextValue',\n _key: targetLanguage,\n value: '', // Start with empty value, transform will fill it\n },\n ])\n .commit()\n }\n\n // Use dot notation path for the locale prompt value\n const localePromptPath = ['localePrompts', { _key: targetLanguage }, 'value']\n\n targets.push({\n // @ts-expect-error\n path: localePromptPath,\n instruction: `You are updating a translation prompt document that contains rules and guidance for future AI translations.\n\nIMPORTANT: The text below is NEW GUIDANCE that should be INCORPORATED INTO the existing prompt as additional rules/instructions for future translations. DO NOT apply or execute these rules on the prompt text itself.\n\nYour task: Merge the new guidance below into the existing prompt text. Treat the new guidance as rules that will guide future translations, not as transformations to apply to the current text.\n\nIntegration guidelines:\n- Add the new guidance as additional instructions/rules in the prompt\n- If it conflicts with existing guidance, update or replace the conflicting parts\n- If it's already covered, don't add redundant text\n- Maintain clear structure and consistent tone\n- Preserve all existing guidance that is still relevant\n- Keep the prompt written as instructions for a translator (e.g., \"When translating, you should...\" not \"The translation has been...\")\n\nNew guidance to incorporate:\n\n\\`\\`\\`\n${combinedLocaleUpdate}\n\\`\\`\\``,\n })\n devLog.debug('Added locale prompt target', {\n targetLanguage,\n localePromptPath,\n combinedUpdate: combinedLocaleUpdate,\n })\n }\n\n // Use transform action with multiple targets\n const result = await client.agent.action.transform({\n schemaId,\n documentId: settingsId,\n instruction: 'Update translation prompts based on user feedback to improve future translations.',\n target: targets,\n forcePublishedWrite: true,\n })\n\n devLog.info('Prompts updated via transform action', {\n resultId: result._id,\n globalUpdated: globalPrompts.length > 0,\n localeUpdated: localePrompts.length > 0,\n })\n}\n\n/**\n * Adds new protected phrases to the translation settings.\n */\nasync function addProtectedPhrases(client: SanityClient, settingsId: string, phrases: string[]): Promise<void> {\n devLog.info('Adding protected phrases', { settingsId, phrasesCount: phrases.length, phrases })\n\n const currentPhrases = await client.fetch<string[]>('*[_id == $settingsId][0].protectedPhrases', { settingsId })\n devLog.debug('Fetched current protected phrases', { currentCount: currentPhrases?.length })\n\n const newPhrases = phrases.filter((phrase) => !currentPhrases?.includes(phrase))\n\n if (newPhrases.length === 0) {\n devLog.info('No new protected phrases to add (all already exist)')\n return\n }\n\n const result = await client\n .patch(settingsId)\n .setIfMissing({ protectedPhrases: [] })\n .append('protectedPhrases', newPhrases)\n .commit()\n\n devLog.info('Protected phrases added', { count: newPhrases.length, phrases: newPhrases, resultId: result._id })\n}\n\n/**\n * Adds new glossary terms or updates existing ones.\n * Creates glossary terms with translations in both source and target languages.\n */\nasync function addGlossaryTerms(\n client: SanityClient,\n terms: Array<{ sourceLocale: string; sourceValue: string; targetLocale: string; targetValue: string }>,\n): Promise<void> {\n // Filter out terms where source === target (these should be protected phrases instead)\n const validTerms = terms.filter(({ sourceValue, targetValue }) => {\n if (sourceValue === targetValue) {\n devLog.warn('Skipping glossary term where source === target (should be a protected phrase)', {\n sourceValue,\n targetValue,\n })\n return false\n }\n return true\n })\n\n if (validTerms.length === 0) {\n devLog.info('No valid glossary terms to add')\n return\n }\n\n for (const { sourceLocale, sourceValue, targetLocale, targetValue } of validTerms) {\n const existingTerm = await client.fetch<{\n _id: string\n translations: Array<{ _key: string; value: string }>\n } | null>(\n `*[_type == \"translationGlossaryTerm\" && count(translations[_key == $sourceLocale && value == $sourceValue]) > 0\n ][0] {\n _id,\n translations\n }`,\n { sourceLocale, sourceValue },\n )\n\n if (existingTerm) {\n const hasTargetTranslation = existingTerm.translations.some((t) => t._key === targetLocale)\n\n if (!hasTargetTranslation) {\n await client\n .patch(existingTerm._id)\n .append('translations', [\n {\n _type: 'internationalizedArrayStringValue',\n _key: targetLocale,\n value: targetValue,\n },\n ])\n .commit()\n\n devLog.info('Updated existing glossary term', { sourceLocale, sourceValue, targetLocale, targetValue })\n } else {\n devLog.info('Glossary term already has this translation', {\n sourceLocale,\n sourceValue,\n targetLocale,\n targetValue,\n })\n }\n } else {\n await client.create({\n _type: 'translationGlossaryTerm',\n translations: [\n {\n _type: 'internationalizedArrayStringValue',\n _key: sourceLocale,\n value: sourceValue,\n },\n {\n _type: 'internationalizedArrayStringValue',\n _key: targetLocale,\n value: targetValue,\n },\n ],\n })\n\n devLog.info('Created new glossary term', { sourceLocale, sourceValue, targetLocale, targetValue })\n }\n }\n\n devLog.info('Glossary terms processed', {\n totalRequested: terms.length,\n validAdded: validTerms.length,\n skipped: terms.length - validTerms.length,\n })\n}\n","import { CheckmarkCircleIcon, ErrorOutlineIcon } from '@sanity/icons'\nimport { Card, type CardTone, Flex, Spinner, Stack, Text } from '@sanity/ui'\nimport type { FC } from 'react'\n\ntype ProgressPanelStatus = 'in_progress' | 'completed' | 'error'\n\ninterface ProgressPanelProps {\n title?: string\n description?: string\n tone?: CardTone\n status?: ProgressPanelStatus\n icon?: React.ReactNode\n}\n\nconst ICON_SIZE = 64\n\nconst progressIconMap: Record<ProgressPanelStatus, React.ReactNode> = {\n in_progress: <Spinner />,\n completed: <CheckmarkCircleIcon fontSize={ICON_SIZE} />,\n error: <ErrorOutlineIcon fontSize={ICON_SIZE} />,\n}\n\nexport const ProgressPanel: FC<ProgressPanelProps> = ({\n title,\n description,\n tone,\n status = 'in_progress',\n icon,\n ...props\n}) => {\n return (\n <Card tone={tone} padding={4} {...props}>\n <Flex gap={4} align=\"center\" justify=\"center\">\n {icon || progressIconMap[status]}\n <Stack space={3}>\n {title && (\n <Text size={2} weight=\"bold\">\n {title}\n </Text>\n )}\n {description && (\n <Text size={1} muted>\n {description}\n </Text>\n )}\n </Stack>\n </Flex>\n </Card>\n )\n}\n","import { AddIcon, EmptyIcon, TrashIcon } from '@sanity/icons'\nimport { Box, Button, Card, Checkbox, Flex, Select, Stack, Text, TextArea, TextInput } from '@sanity/ui'\nimport { type FC, useState } from 'react'\nimport type { FeedbackSuggestion, ImprovementType } from '../types'\nimport { ProgressPanel } from './ProgressPanel'\n\ninterface SuggestionReviewListProps {\n suggestions: FeedbackSuggestion[]\n onSuggestionsChange: (suggestions: FeedbackSuggestion[]) => void\n}\n\nconst IMPROVEMENT_TYPE_LABELS: Record<ImprovementType, string> = {\n globalPrompt: 'Global Prompt',\n localePrompt: 'Locale Prompt',\n protectedPhrase: 'Protected Phrase',\n glossaryTerm: 'Glossary Term',\n}\n\n/**\n * Creates a new empty suggestion with default values\n */\nconst createNewSuggestion = (type: ImprovementType = 'protectedPhrase'): FeedbackSuggestion => {\n const baseSuggestion: FeedbackSuggestion = {\n id: crypto.randomUUID(),\n type,\n description: '',\n approved: true,\n }\n\n if (type === 'glossaryTerm') {\n return {\n ...baseSuggestion,\n sourceValue: '',\n targetValue: '',\n }\n }\n\n return baseSuggestion\n}\n\nexport const SuggestionReviewList: FC<SuggestionReviewListProps> = ({ suggestions, onSuggestionsChange }) => {\n const [editingId, setEditingId] = useState<string | null>(null)\n\n const handleToggleApproval = (id: string) => {\n const updated = suggestions.map((s) => (s.id === id ? { ...s, approved: !s.approved } : s))\n onSuggestionsChange(updated)\n }\n\n const handleTypeChange = (id: string, newType: ImprovementType) => {\n const updated = suggestions.map((s) => {\n if (s.id !== id) {\n return s\n }\n\n // If changing to/from glossaryTerm, we need to handle sourceValue/targetValue\n if (newType === 'glossaryTerm' && s.type !== 'glossaryTerm') {\n // Parse description if it looks like \"source → target\"\n const match = s.description.match(/^(.+?)\\s*→\\s*(.+)$/)\n return {\n ...s,\n type: newType,\n sourceValue: match ? match[1].trim() : '',\n targetValue: match ? match[2].trim() : '',\n }\n }\n if (newType !== 'glossaryTerm' && s.type === 'glossaryTerm') {\n // Convert back to simple description\n return {\n ...s,\n type: newType,\n description: s.sourceValue && s.targetValue ? `${s.sourceValue} → ${s.targetValue}` : s.description,\n sourceValue: undefined,\n targetValue: undefined,\n }\n }\n return { ...s, type: newType }\n })\n onSuggestionsChange(updated)\n }\n\n const handleDescriptionChange = (id: string, newDescription: string) => {\n const updated = suggestions.map((s) => (s.id === id ? { ...s, description: newDescription } : s))\n onSuggestionsChange(updated)\n }\n\n const handleGlossarySourceChange = (id: string, newSource: string) => {\n const updated = suggestions.map((s) =>\n s.id === id\n ? {\n ...s,\n sourceValue: newSource,\n description: `${newSource} → ${s.targetValue || ''}`,\n }\n : s,\n )\n onSuggestionsChange(updated)\n }\n\n const handleGlossaryTargetChange = (id: string, newTarget: string) => {\n const updated = suggestions.map((s) =>\n s.id === id\n ? {\n ...s,\n targetValue: newTarget,\n description: `${s.sourceValue || ''} → ${newTarget}`,\n }\n : s,\n )\n onSuggestionsChange(updated)\n }\n\n const handleRemove = (id: string) => {\n const updated = suggestions.filter((s) => s.id !== id)\n onSuggestionsChange(updated)\n }\n\n const handleAddSuggestion = (type: ImprovementType) => {\n const newSuggestion = createNewSuggestion(type)\n onSuggestionsChange([...suggestions, newSuggestion])\n // Auto-focus on the new suggestion by setting it as editing\n setEditingId(newSuggestion.id)\n }\n\n if (suggestions.length === 0) {\n return (\n <Stack space={3}>\n <ProgressPanel\n status=\"error\"\n tone=\"transparent\"\n title=\"No suggestions generated\"\n description='Try providing more specific feedback or enabling \"Include Edits\".'\n icon={<EmptyIcon fontSize={24} />}\n />\n <Flex justify=\"flex-start\">\n <Button\n mode=\"ghost\"\n tone=\"primary\"\n icon={AddIcon}\n text=\"Add Suggestion\"\n fontSize={1}\n onClick={() => handleAddSuggestion('protectedPhrase')}\n />\n </Flex>\n </Stack>\n )\n }\n\n return (\n <Stack space={3}>\n {suggestions.map((suggestion) => {\n const isEditing = editingId === suggestion.id\n const isGlossaryTerm = suggestion.type === 'glossaryTerm'\n const isPrompt = suggestion.type === 'globalPrompt' || suggestion.type === 'localePrompt'\n\n return (\n <Card\n key={suggestion.id}\n padding={4}\n border\n tone={suggestion.approved ? 'default' : 'transparent'}\n style={{ opacity: suggestion.approved ? 1 : 0.5 }}\n >\n <Stack space={3}>\n <Flex align=\"flex-start\" gap={3}>\n <Box paddingTop={1}>\n <Checkbox checked={suggestion.approved} onChange={() => handleToggleApproval(suggestion.id)} />\n </Box>\n\n <Stack space={3} flex={1}>\n <Flex gap={2} align=\"center\" wrap=\"wrap\">\n <Box flex={1} style={{ minWidth: '200px' }}>\n <Select\n fontSize={1}\n value={suggestion.type}\n onChange={(event) =>\n handleTypeChange(suggestion.id, event.currentTarget.value as ImprovementType)\n }\n >\n {Object.entries(IMPROVEMENT_TYPE_LABELS).map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </Select>\n </Box>\n\n <Button\n mode=\"bleed\"\n tone=\"critical\"\n icon={TrashIcon}\n fontSize={1}\n padding={2}\n onClick={() => handleRemove(suggestion.id)}\n />\n </Flex>\n\n {isGlossaryTerm ? (\n <Stack space={2}>\n <Flex gap={2} align=\"center\">\n <Box flex={1}>\n <TextInput\n fontSize={1}\n placeholder=\"Source term\"\n value={suggestion.sourceValue || ''}\n onChange={(event) => handleGlossarySourceChange(suggestion.id, event.currentTarget.value)}\n />\n </Box>\n <Text size={1} muted>\n →\n </Text>\n <Box flex={1}>\n <TextInput\n fontSize={1}\n placeholder=\"Target term\"\n value={suggestion.targetValue || ''}\n onChange={(event) => handleGlossaryTargetChange(suggestion.id, event.currentTarget.value)}\n />\n </Box>\n </Flex>\n </Stack>\n ) : isPrompt ? (\n <Stack space={2}>\n <TextArea\n fontSize={1}\n rows={isEditing ? 6 : 3}\n value={suggestion.description}\n onChange={(event) => handleDescriptionChange(suggestion.id, event.currentTarget.value)}\n onFocus={() => setEditingId(suggestion.id)}\n onBlur={() => setEditingId(null)}\n placeholder=\"Enter prompt guidance...\"\n />\n </Stack>\n ) : (\n <TextInput\n fontSize={1}\n value={suggestion.description}\n onChange={(event) => handleDescriptionChange(suggestion.id, event.currentTarget.value)}\n placeholder=\"Enter protected phrase...\"\n />\n )}\n </Stack>\n </Flex>\n </Stack>\n </Card>\n )\n })}\n\n <Flex justify=\"flex-start\">\n <Button\n mode=\"ghost\"\n tone=\"neutral\"\n icon={AddIcon}\n text=\"Add Suggestion\"\n fontSize={1}\n onClick={() => handleAddSuggestion('protectedPhrase')}\n />\n </Flex>\n </Stack>\n )\n}\n","import { ArrowLeftIcon, EditIcon, InfoOutlineIcon } from '@sanity/icons'\nimport { Box, Button, Card, Checkbox, Flex, Heading, Inline, Stack, Text, TextArea, Tooltip } from '@sanity/ui'\nimport { type FC, useState } from 'react'\nimport { useClient } from 'sanity'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { useTranslationMetadata } from '../hooks/useTranslationMetadata'\nimport type { FeedbackSuggestion } from '../types'\nimport { analyzeFeedback, applySuggestions } from '../utils/processFeedback'\nimport { ProgressPanel } from './ProgressPanel'\nimport { SuggestionReviewList } from './SuggestionReviewList'\n\ninterface GiveFeedbackDialogProps {\n setIsDialogOpen: (isOpen: boolean) => void\n}\n\ntype ProcessingState = 'idle' | 'analyzing' | 'reviewing' | 'applying' | 'completed' | 'error'\n\nexport const GiveFeedbackDialog: FC<GiveFeedbackDialogProps> = ({ setIsDialogOpen }) => {\n const client = useClient({ apiVersion: 'vX' })\n const { document, config, translationMetadata } = useTranslationContext()\n const { loading } = useTranslationMetadata({\n documentId: document._id,\n })\n\n const [feedback, setFeedback] = useState('')\n const [shouldIncludeEdits, setShouldIncludeEdits] = useState(false)\n const [processingState, setProcessingState] = useState<ProcessingState>('idle')\n const [suggestions, setSuggestions] = useState<FeedbackSuggestion[]>([])\n const [changeSummary, setChangeSummary] = useState<string>('')\n const [error, setError] = useState<string>('')\n\n const handleShouldIncludeEditsChange = () => {\n setShouldIncludeEdits(!shouldIncludeEdits)\n }\n\n const handleCancel = () => {\n setIsDialogOpen(false)\n }\n\n const handleAnalyze = async () => {\n if (!feedback && !shouldIncludeEdits) {\n setError('Please provide feedback or enable \"Include Edits\"')\n return\n }\n\n if (!config) {\n setError('Missing plugin configuration')\n return\n }\n\n setError('')\n setProcessingState('analyzing')\n setChangeSummary('')\n\n try {\n const translationHistory = translationMetadata?.translationHistory?.find(\n (history) => history.language === document[config.languageFieldName],\n )\n\n if (!translationHistory) {\n throw new Error(\n 'No translation history found for this document. Please ensure this document was translated using the AI Translation plugin.',\n )\n }\n\n const { sourceSnapshot, targetSnapshot, sourceLanguage } = translationHistory\n\n if (!sourceSnapshot || !targetSnapshot) {\n throw new Error('Translation snapshots are missing from history.')\n }\n\n // Analyze the feedback using the AI agent\n const generatedSuggestions = await analyzeFeedback({\n client,\n schemaId: config.schemaId,\n sourceLanguage: sourceLanguage || 'en-us',\n targetLanguage: document[config.languageFieldName] as string,\n userFeedback: feedback || undefined,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument: shouldIncludeEdits ? document : undefined,\n onProgress: ({ stage, message }) => {\n setProcessingState(stage)\n setChangeSummary(message)\n },\n })\n\n setSuggestions(generatedSuggestions)\n setProcessingState('reviewing')\n } catch (err) {\n console.error('Error analyzing feedback:', err)\n setError(err instanceof Error ? err.message : 'An unexpected error occurred')\n setProcessingState('error')\n }\n }\n\n const handleApplySuggestions = async () => {\n if (!config) {\n setError('Missing plugin configuration')\n return\n }\n\n const approvedCount = suggestions.filter((s) => s.approved).length\n if (approvedCount === 0) {\n setError('Please approve at least one suggestion to apply')\n return\n }\n\n setError('')\n setProcessingState('applying')\n\n try {\n const translationHistory = translationMetadata?.translationHistory?.find(\n (history) => history.language === document[config.languageFieldName],\n )\n\n if (!translationHistory) {\n throw new Error('Translation history not found')\n }\n\n await applySuggestions({\n client,\n schemaId: config.schemaId,\n sourceLanguage: translationHistory.sourceLanguage || 'en-us',\n targetLanguage: translationHistory.language,\n suggestions,\n onProgress: ({ stage, message }) => {\n setProcessingState(stage)\n setChangeSummary(message)\n },\n })\n\n setProcessingState('completed')\n } catch (err) {\n console.error('Error applying suggestions:', err)\n setError(err instanceof Error ? err.message : 'An unexpected error occurred')\n setProcessingState('error')\n }\n }\n\n if (loading) {\n return <ProgressPanel title=\"Loading translation metadata\" />\n }\n\n // Show analyzing state\n if (processingState === 'analyzing') {\n return <ProgressPanel title=\"Analyzing feedback with AI...\" description={changeSummary} />\n }\n\n // Show review state\n if (processingState === 'reviewing') {\n return (\n <Stack space={4}>\n <Stack space={4}>\n <Heading>Review Suggestions</Heading>\n <Text muted>\n The AI has analyzed your feedback and generated the following suggestions. Review and edit them before\n applying.\n </Text>\n </Stack>\n\n <SuggestionReviewList suggestions={suggestions} onSuggestionsChange={setSuggestions} />\n\n {error && (\n <Card padding={3} tone=\"critical\" border>\n <Text size={1}>{error}</Text>\n </Card>\n )}\n\n <Flex justify=\"space-between\" gap={2} paddingTop={2}>\n <Flex gap={2}>\n <Button\n type=\"button\"\n mode=\"bleed\"\n tone=\"neutral\"\n onClick={() => setProcessingState('idle')}\n icon={<ArrowLeftIcon />}\n text=\"Back\"\n />\n </Flex>\n <Button\n type=\"button\"\n mode=\"ghost\"\n tone=\"positive\"\n size={1}\n onClick={handleApplySuggestions}\n disabled={suggestions.filter((s) => s.approved).length === 0}\n >\n Apply {suggestions.filter((s) => s.approved).length} Suggestion\n {suggestions.filter((s) => s.approved).length !== 1 ? 's' : ''}\n </Button>\n </Flex>\n </Stack>\n )\n }\n\n // Show applying state\n if (processingState === 'applying') {\n return <ProgressPanel title=\"Updating translation settings...\" description={changeSummary} icon={<EditIcon />} />\n }\n\n // Show completion state\n if (processingState === 'completed') {\n const appliedCount = suggestions.filter((s) => s.approved).length\n const description = `${appliedCount} suggestion${appliedCount !== 1 ? 's' : ''} applied. Translation prompts and glossary havebeen updated based on your feedback.`\n return (\n <Box padding={4}>\n <ProgressPanel title=\"Translation settings updated\" description={description} status=\"completed\" />\n\n <Flex justify=\"flex-end\" paddingTop={3}>\n <Button type=\"button\" mode=\"ghost\" tone=\"primary\" size={1} onClick={handleCancel}>\n Close\n </Button>\n </Flex>\n </Box>\n )\n }\n\n // Show error state\n if (processingState === 'error') {\n return (\n <Box padding={4}>\n <Stack space={4}>\n <ProgressPanel status=\"error\" title=\"Error processing feedback\" description={error} tone=\"critical\" />\n <Flex justify=\"flex-end\" gap={2}>\n <Button type=\"button\" mode=\"ghost\" onClick={handleCancel}>\n Close\n </Button>\n <Button type=\"reset\" mode=\"ghost\" tone=\"primary\" onClick={() => setProcessingState('idle')}>\n Reset\n </Button>\n </Flex>\n </Stack>\n </Box>\n )\n }\n\n // Default form view\n return (\n <Stack space={4}>\n <Card tone=\"transparent\" padding={4}>\n <Stack space={4}>\n <Stack space={2}>\n <Stack space={4}>\n <Inline space={2}>\n <Text size={2} muted>\n Enter your feedback for the translation AI agent.\n </Text>\n <Tooltip\n portal\n content={\n <Box padding={2} style={{ maxWidth: '280px' }}>\n <Text size={1}>\n The AI agent will use your feedback to improve translation prompts, update protected phrases,\n and modify the glossary. Be specific about what should be changed.\n </Text>\n </Box>\n }\n >\n <Text size={1}>\n <InfoOutlineIcon />\n </Text>\n </Tooltip>\n </Inline>\n <TextArea\n rows={8}\n fontSize={2}\n onChange={(event) => setFeedback(event.currentTarget.value)}\n padding={3}\n placeholder='Example: \"Braze\" is a branded term and should not be translated.'\n value={feedback}\n />\n </Stack>\n </Stack>\n\n <Stack space={2}>\n <Stack space={3}>\n <Button\n type=\"button\"\n mode={shouldIncludeEdits ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleShouldIncludeEditsChange}\n tone={shouldIncludeEdits ? 'primary' : 'default'}\n >\n <Flex align=\"flex-start\" gap={3}>\n <Box paddingTop={1}>\n <Checkbox checked={shouldIncludeEdits} readOnly style={{ pointerEvents: 'none' }} />\n </Box>\n <Stack space={2} flex={1}>\n <Text size={2} weight=\"medium\">\n Include Edits in Feedback\n </Text>\n <Text size={1} muted style={{ textAlign: 'left' }}>\n The AI will analyze edits you made to the translation.\n </Text>\n </Stack>\n </Flex>\n </Button>\n </Stack>\n </Stack>\n </Stack>\n </Card>\n <Flex justify=\"flex-end\" gap={2} paddingTop={2}>\n <Button type=\"button\" mode=\"ghost\" size={1} onClick={handleCancel}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n mode=\"ghost\"\n tone=\"positive\"\n size={1}\n onClick={handleAnalyze}\n disabled={!feedback.trim() && !shouldIncludeEdits}\n >\n Analyze Feedback\n </Button>\n </Flex>\n </Stack>\n )\n}\n","import defaults from 'lodash.defaults'\nimport type { TranslationAction, TranslationContext } from '../../types'\nimport { devLog } from '../../utils/devLog'\n\nexport const translationReducer = (\n context: Omit<TranslationContext, 'dispatch'>,\n action: TranslationAction,\n): Omit<TranslationContext, 'dispatch'> => {\n const logContext = {\n documentId: context.document?._id,\n actionType: action.type,\n component: 'translationReducer',\n }\n\n devLog.debug('Translation action dispatched', {\n ...logContext,\n payload: action.payload,\n })\n\n switch (action.type) {\n case 'SET_OVERALL_STATUS':\n return { ...context, overallStatus: action.payload }\n\n case 'SET_TRANSLATION_METADATA':\n return { ...context, translationMetadata: action.payload }\n\n case 'SET_SELECTED_TARGET_LANGUAGES':\n return {\n ...context,\n selectedTargetLanguages: action.payload,\n }\n\n case 'SET_SHOULD_TRANSLATE_DIFFS':\n return {\n ...context,\n shouldTranslateDiffs: action.payload,\n }\n\n case 'SET_SHOULD_TRANSLATE_REFERENCES':\n return {\n ...context,\n shouldTranslateReferences: action.payload,\n }\n\n case 'SET_MAX_REFERENCE_DEPTH':\n return {\n ...context,\n maxReferenceDepth: action.payload,\n }\n\n case 'SET_SHOULD_OVERWRITE_FRESH_TRANSLATIONS':\n return {\n ...context,\n shouldOverwriteFreshTranslations: action.payload,\n }\n\n case 'SET_REFERENCES':\n return {\n ...context,\n references: action.payload,\n }\n\n case 'SET_TRANSLATION_JOB_STATUS': {\n // Create a unique key for each job using both document ID and language\n // This ensures concurrent translations to different languages don't conflict\n const jobKey = `${action.payload._id}_${action.payload.language}`\n\n // Create a new Map to trigger React re-render (immutability)\n const newTranslationJobs = new Map(context.translationJobs)\n\n newTranslationJobs.set(jobKey, defaults(action.payload, newTranslationJobs.get(jobKey)))\n\n return {\n ...context,\n translationJobs: newTranslationJobs,\n }\n }\n\n default:\n return context\n }\n}\n","import { type FC, useReducer } from 'react'\nimport type { PluginConfig, TranslatableDocument, TranslationContext as TTranslationContext } from '../../types'\nimport { devLog } from '../../utils/devLog'\nimport { TranslationContext } from './TranslationContext'\nimport { translationReducer } from './translationReducer'\n\ninterface TranslationContextProviderProps {\n document: TranslatableDocument\n config: PluginConfig\n children: React.ReactNode\n}\n\nexport const TranslationContextProvider: FC<TranslationContextProviderProps> = ({ document, config, children }) => {\n devLog.debug('TranslationContextProvider initialized', {\n documentId: document._id,\n documentType: document._type,\n supportedLanguages: config.supportedLanguages?.map((l) => l.id),\n component: 'TranslationContextProvider',\n })\n\n const initialContext: Omit<TTranslationContext, 'dispatch'> = {\n document,\n config,\n overallStatus: 'idle',\n translationMetadata: null,\n selectedTargetLanguages: [],\n shouldTranslateDiffs: false,\n shouldOverwriteFreshTranslations: false,\n shouldTranslateReferences: false,\n maxReferenceDepth: 1,\n references: [],\n translationJobs: new Map(),\n }\n\n const [context, dispatch] = useReducer(translationReducer, initialContext)\n\n devLog.debug('Translation context state initialized', {\n documentId: document._id,\n overallStatus: context.overallStatus,\n selectedLanguages: context.selectedTargetLanguages,\n shouldTranslateDiffs: context.shouldTranslateDiffs,\n component: 'TranslationContextProvider',\n })\n\n return <TranslationContext.Provider value={{ ...context, dispatch }}>{children}</TranslationContext.Provider>\n}\n","import { TranslateIcon } from '@sanity/icons'\nimport { useState } from 'react'\nimport type { DocumentActionDescription, DocumentActionProps } from 'sanity'\nimport { GiveFeedbackDialog } from './components/GiveFeedbackDialog'\nimport { TranslationContextProvider } from './hooks/useTranslationContext/TranslationContextProvider'\nimport type { PluginConfig, TranslatableDocument } from './types'\nimport { devLog } from './utils/devLog'\n\ninterface TranslateActionProps extends DocumentActionProps {\n config: PluginConfig\n}\n\nexport const getGiveTranslationFeedbackAction = (config: PluginConfig) => {\n return ({ draft, published }: TranslateActionProps): DocumentActionDescription | null => {\n const document = draft ?? published\n const [isDialogOpen, setIsDialogOpen] = useState(false)\n\n devLog.debug('ImproveTranslationPromptsAction initialized', {\n documentId: document?._id,\n documentType: document?._type,\n })\n\n if (!document || !config.translatableSchemaTypes?.includes(document._type)) {\n devLog.warn('Document not in translatable schema types', {\n documentType: document?._type,\n translatableTypes: config.translatableSchemaTypes,\n })\n return null\n }\n\n if (!config) {\n devLog.error('Missing config in TranslateAction')\n return null\n }\n\n return {\n label: 'Give Translation Feedback',\n icon: TranslateIcon,\n onHandle: () => {\n devLog.info('Give Translation Feedback dialog opened', {\n documentId: document._id,\n documentType: document._type,\n component: 'GiveTranslationFeedbackAction',\n })\n setIsDialogOpen(true)\n },\n dialog: isDialogOpen && {\n type: 'dialog',\n onClose: () => setIsDialogOpen(false),\n header: 'Give Translation Feedback',\n content: (\n <TranslationContextProvider document={document as TranslatableDocument} config={config}>\n <GiveFeedbackDialog setIsDialogOpen={setIsDialogOpen} />\n </TranslationContextProvider>\n ),\n },\n }\n }\n}\n","import { TranslateIcon } from '@sanity/icons'\nimport { defineField, defineType } from 'sanity'\n\nexport const translationGlossaryTerm = defineType({\n name: 'translationGlossaryTerm',\n title: 'Translation Glossary Term',\n icon: TranslateIcon,\n type: 'document',\n fields: [\n defineField({\n name: 'translations',\n title: 'Translations',\n type: 'internationalizedArrayString',\n }),\n ],\n preview: {\n select: {\n translations: 'translations',\n },\n prepare({ translations }: { translations: { locale: string; value: string }[] }) {\n const enTranslation = translations?.find((t) => t.locale === 'en-us')\n const firstTranslation = translations?.[0]\n return {\n title: enTranslation?.value || firstTranslation?.value || 'No translation available',\n }\n },\n },\n})\n","import { defineField } from 'sanity'\n\nexport const translationHistory = defineField({\n name: 'translationHistory',\n type: 'array',\n of: [\n {\n name: 'targetLanguageHistory',\n type: 'object',\n fields: [\n defineField({\n name: 'language',\n title: 'Language',\n description: 'The language of the target document',\n type: 'string',\n }),\n defineField({\n name: 'sourceId',\n title: 'Source ID',\n description: 'The ID of the source document',\n type: 'string',\n }),\n defineField({\n name: 'sourceRev',\n title: 'Source Revision',\n description: 'The revision ID of the source document at the time of translation',\n type: 'string',\n }),\n defineField({\n name: 'sourceLanguage',\n title: 'Source Language',\n description: 'The language of the source document',\n type: 'string',\n }),\n defineField({\n name: 'sourceSnapshot',\n title: 'Source Snapshot',\n description: 'The snapshot of the source document at the time of translation',\n type: 'text',\n }),\n defineField({\n name: 'targetId',\n title: 'Target ID',\n description: 'The ID of the target document',\n type: 'string',\n }),\n ],\n },\n ],\n})\n","import { TranslateIcon } from '@sanity/icons'\nimport { defineField, defineType } from 'sanity'\n\nexport const translationSettings = defineType({\n name: 'translationSettings',\n title: 'Translation Settings',\n icon: TranslateIcon,\n type: 'document',\n fields: [\n defineField({\n name: 'globalPrompt',\n title: 'Global Translation Prompt',\n description: 'A prompt that will given to the Sanity AI Agent for all translation tasks.',\n type: 'text',\n rows: 5,\n }),\n defineField({\n name: 'localePrompts',\n title: 'Locale Prompts',\n description: 'Prompts that will be given to the Sanity AI Agent for each locale.',\n type: 'internationalizedArrayText',\n }),\n defineField({\n name: 'protectedPhrases',\n title: 'Protected Phrases',\n description: 'Phrases that will never be translated.',\n type: 'array',\n of: [{ type: 'string' }],\n }),\n ],\n preview: {\n prepare: () => ({\n title: 'Translation Settings',\n }),\n },\n})\n","import type { SanityClient } from 'sanity'\nimport type { TranslationGlossaryTermDocument, TranslationSettingsDocument } from '../types'\n\ninterface FetchTranslationPromptsOptions {\n client: SanityClient\n sourceLanguage?: string\n targetLanguages: Array<string>\n}\n\nexport interface FetchTranslationPromptsResult {\n globalPrompt?: string\n protectedPhrases?: Array<string>\n localeInstructions: Record<\n string,\n {\n prompt?: string\n glossaryTerms?: string\n }\n >\n}\n\nexport const fetchTranslationPrompts = async ({\n client,\n sourceLanguage,\n targetLanguages,\n}: FetchTranslationPromptsOptions): Promise<FetchTranslationPromptsResult> => {\n const translationSettings = await client.fetch<TranslationSettingsDocument | null>(\n `*[_id == \"translation-settings\"][0] {\n globalPrompt,\n localePrompts[locale in $targetLanguages],\n protectedPhrases\n }`,\n { targetLanguages },\n )\n\n // Fetch all translation glossary terms that have a translation in both the source and target languages\n const translationGlossaryTerms =\n (await client.fetch<Array<NonNullable<TranslationGlossaryTermDocument['translations']>> | null>(\n `*[\n _type == \"translationGlossaryTerm\"\n && count(translations[locale in $targetLanguages]) > 0\n && count(translations[locale == $sourceLanguage]) > 0\n ].translations`,\n { targetLanguages, sourceLanguage },\n )) || []\n\n const glossaryTermsByLocale: Record<string, Array<{ from: string; to: string }>> = {}\n\n for (const targetLanguage of targetLanguages) {\n const relevantTerms = translationGlossaryTerms.filter((termTranslations) =>\n termTranslations.some((translation) => translation._key === targetLanguage),\n )\n\n const relevantTranslations = relevantTerms\n .map((termTranslations) => {\n const from = termTranslations.find((translation) => translation._key === sourceLanguage)?.value\n const to = termTranslations.find((translation) => translation._key === targetLanguage)?.value\n if (!from || !to) {\n return null\n }\n return { from, to }\n })\n .filter((item): item is { from: string; to: string } => item !== null) // brow-beating the Typescript compiler since `filter(Boolean)` doesn't register correctly// brow-beating the Typescript compiler since `filter(Boolean)` doesn't register correctly\n\n glossaryTermsByLocale[targetLanguage] = relevantTranslations\n }\n\n return {\n globalPrompt: translationSettings?.globalPrompt,\n protectedPhrases: translationSettings?.protectedPhrases,\n localeInstructions: Object.fromEntries(\n targetLanguages.map((locale) => [\n locale,\n {\n prompt: translationSettings?.localePrompts?.find((lp) => lp._key === locale)?.value,\n glossaryTerms: formatGlossaryTermInstruction(glossaryTermsByLocale[locale]),\n },\n ]),\n ),\n }\n}\n\nconst formatGlossaryTermInstruction = (terms: Array<{ from: string; to: string }>) => {\n const instructions = [\n 'Translate the following terms exactly as described below. When a term includes a colon, the suffix following the colon describes how the term should be translated for the female gender.',\n ]\n\n terms.forEach(({ from, to }) => {\n instructions.push(`\"${from}\" -> \"${to}\"`)\n })\n\n return instructions.join('\\n')\n}\n","export type RecursiveSearchable =\n | null\n | undefined\n | string\n | number\n | boolean\n | RecursiveSearchable[]\n | { [key: string]: RecursiveSearchable }\n\nexport type FindKeyValueResult<T = unknown> = {\n value: T\n path: Array<string | number>\n}\n\n/**\n * Recursively searches through an object/array structure to find all values\n * associated with a specific key name, along with their paths.\n *\n * @param obj - The object or array to search through\n * @param targetKey - The key name to search for\n * @returns An array of objects containing the value and path for each occurrence of the target key\n */\nexport const findKeyValues = <T = unknown>(obj: RecursiveSearchable, targetKey: string): FindKeyValueResult<T>[] => {\n const results: FindKeyValueResult<T>[] = []\n\n const recursiveSearch = (current: RecursiveSearchable, currentPath: Array<string | number>): void => {\n // Handle null/undefined\n if (current === null || current === undefined) {\n return\n }\n\n // If current item is an array, search each element\n if (Array.isArray(current)) {\n current.forEach((item, index) => {\n recursiveSearch(item, [...currentPath, index])\n })\n return\n }\n\n // If current item is an object\n if (typeof current === 'object') {\n for (const [key, value] of Object.entries(current)) {\n const newPath = [...currentPath, key]\n\n // If we found the target key, add its value and path to our results\n if (key === targetKey) {\n results.push({\n value: value as T,\n path: newPath,\n })\n }\n\n // Continue searching recursively\n recursiveSearch(value, newPath)\n }\n }\n }\n\n recursiveSearch(obj, [])\n return results\n}\n","import { pathToString, type SanityClient } from 'sanity'\nimport { TRANSLATION_METADATA_TYPE } from '../consts'\nimport type { PluginConfig } from '../types'\nimport { type FindKeyValueResult, findKeyValues } from './findKeyValues'\nimport { undraftId } from './undraftId'\n\ninterface LocalizeReferenceParams {\n client: SanityClient\n documentId: string\n languageFieldName: PluginConfig['languageFieldName']\n}\n\nexport const localizeReferences = async ({ client, documentId, languageFieldName }: LocalizeReferenceParams) => {\n try {\n const doc = await client.fetch('*[_id == $documentId][0]', { documentId })\n\n if (!doc) {\n console.error(documentId, 'not found')\n return\n }\n\n const targetLanguage = doc[languageFieldName]\n\n if (!targetLanguage) {\n console.error(documentId, 'no value found for language field:', languageFieldName)\n return\n }\n\n const refs = findKeyValues<string>(doc, '_ref')\n\n if (!refs?.length) {\n return\n }\n\n await updateReferences(documentId, client, refs, targetLanguage)\n } catch (error) {\n console.error('Error localizing references:', error)\n }\n}\n\nexport const updateReferences = async (\n documentId: string,\n client: SanityClient,\n refs: Array<FindKeyValueResult<string>>,\n targetLanguage: string,\n) => {\n const patch = client.patch(documentId)\n\n if (!refs?.length) {\n return []\n }\n\n for (const ref of refs) {\n const newId = await client.fetch<string | null>(\n '(*[_type == $translationMetadataSchemaType && references($sourceId)].translations[_key == $targetLanguage].value._ref)[0]',\n {\n translationMetadataSchemaType: TRANSLATION_METADATA_TYPE,\n sourceId: undraftId(ref.value),\n targetLanguage,\n },\n )\n\n if (!newId) {\n // No matching translation found for the reference. The document might not have been translated yet\n // or might not be of a translatable schema type.\n continue\n }\n\n patch.set({ [pathToString(ref.path)]: undraftId(newId) })\n patch.set({ [`${pathToString(ref.path.slice(0, -1))}._weak`]: true })\n patch.set({\n [`${pathToString(ref.path.slice(0, -1))}._strengthenOnPublish`]: {\n _type: 'reference',\n _weak: false,\n },\n })\n\n await patch.commit()\n }\n}\n","/**\n * Semaphore class for rate limiting concurrent operations\n * Ensures that only a specified number of operations can run simultaneously\n */\nexport class Semaphore {\n private permits: number\n private queue: Array<() => void> = []\n\n constructor(permits: number) {\n this.permits = permits\n }\n\n /**\n * Acquire a permit from the semaphore\n * If no permits are available, the caller will wait until one becomes available\n */\n async acquire(): Promise<void> {\n if (this.permits > 0) {\n this.permits--\n return Promise.resolve()\n }\n\n // Wait for a permit to become available\n return new Promise<void>((resolve) => {\n this.queue.push(resolve)\n })\n }\n\n /**\n * Release a permit back to the semaphore\n * If there are waiting callers, one will be woken up\n */\n release(): void {\n const next = this.queue.shift()\n if (next) {\n // Give the permit to the next waiting caller\n next()\n } else {\n // No one is waiting, increment the available permits\n this.permits++\n }\n }\n\n /**\n * Execute a function with semaphore protection\n * Automatically acquires and releases the permit\n */\n async withPermit<T>(fn: () => Promise<T>): Promise<T> {\n await this.acquire()\n try {\n return await fn()\n } finally {\n this.release()\n }\n }\n\n /**\n * Get the number of available permits\n */\n availablePermits(): number {\n return this.permits\n }\n\n /**\n * Get the number of waiting callers\n */\n queueLength(): number {\n return this.queue.length\n }\n\n /**\n * Update the number of permits\n * If increasing permits, waiting callers will be notified\n * If decreasing permits below current available, available permits will be reduced\n */\n updatePermits(newPermits: number): void {\n const currentTotal = this.permits + this.queue.length\n const difference = newPermits - currentTotal\n\n if (difference > 0) {\n // Increasing permits - wake up waiting callers or add to available permits\n for (let i = 0; i < difference && this.queue.length > 0; i++) {\n const next = this.queue.shift()\n if (next) next()\n }\n // Add any remaining permits to available count\n const remainingIncrease = difference - (currentTotal - this.permits - this.queue.length)\n if (remainingIncrease > 0) {\n this.permits += remainingIncrease\n }\n } else if (difference < 0) {\n // Decreasing permits - reduce available permits (but don't interrupt running operations)\n this.permits = Math.max(0, this.permits + difference)\n }\n }\n}\n","import type { Dispatch } from 'react'\nimport type { SetTranslationJobStatusAction, TranslationAction } from '../types'\n\nexport const setupTranslationJobStatuses = (\n dispatch: Dispatch<TranslationAction>,\n sourceDocuments: Array<{\n _id: string\n _type: string\n title?: string\n }>,\n targetLanguages: Array<string>,\n) => {\n for (const sourceDocument of sourceDocuments) {\n for (const lang of targetLanguages) {\n const payload: SetTranslationJobStatusAction['payload'] = {\n _id: sourceDocument._id,\n _type: sourceDocument._type,\n language: lang,\n status: 'queued',\n title: sourceDocument.title,\n }\n\n dispatch({\n type: 'SET_TRANSLATION_JOB_STATUS',\n payload,\n })\n }\n }\n}\n","import type { PluginConfig, TranslationMetadataDocument } from '../types'\n\nexport const getExistingTranslationId = (\n translationMetadata: TranslationMetadataDocument,\n targetLanguage: PluginConfig['supportedLanguages'][number]['id'],\n): string | null => {\n if (!translationMetadata?.translations?.length) {\n return null\n }\n\n const existingTranslation = translationMetadata.translations.find(\n (translation) => translation._key === targetLanguage,\n )\n\n return existingTranslation?.value._ref || null\n}\n","import type { PluginConfig, TranslationMetadataDocument } from '../types'\nimport { getExistingTranslationId } from './getExistingTranslationId'\n\ninterface DetermineTranslationTargetParams {\n translationMetadata: TranslationMetadataDocument\n targetLanguage: PluginConfig['supportedLanguages'][number]['id']\n}\n\nexport const determineTranslationTarget = ({\n translationMetadata,\n targetLanguage,\n}: DetermineTranslationTargetParams) => {\n const existingTranslationId = getExistingTranslationId(translationMetadata, targetLanguage)\n\n return existingTranslationId\n ? {\n // Update existing translation\n operation: 'createOrReplace' as const,\n _id: existingTranslationId,\n }\n : {\n // Create new translation\n operation: 'create' as const,\n }\n}\n","import type { SanityClient } from 'sanity'\nimport { TRANSLATION_METADATA_TYPE } from '../consts'\nimport type { TranslatableDocument, TranslationMetadataDocument } from '../types'\nimport { undraftId } from './undraftId'\n\ninterface PrepareTranslationMetadataParams {\n client: SanityClient\n sourceDocument: TranslatableDocument\n sourceLanguage: string\n}\n\nexport const getTranslationMetadata = async ({\n client,\n sourceDocument,\n sourceLanguage,\n}: PrepareTranslationMetadataParams): Promise<TranslationMetadataDocument> => {\n try {\n const existingDoc = await client.fetch<TranslationMetadataDocument | null>(\n '*[_type == $tmType && references($sourceDocumentId)][0]',\n {\n tmType: TRANSLATION_METADATA_TYPE,\n sourceDocumentId: undraftId(sourceDocument._id),\n },\n )\n\n if (existingDoc) {\n return existingDoc\n }\n\n const newDoc = (await client.create({\n _type: TRANSLATION_METADATA_TYPE,\n translations: [\n {\n _key: sourceLanguage,\n _type: 'internationalizedArrayReferenceValue',\n value: {\n _type: 'reference',\n _ref: undraftId(sourceDocument._id),\n _weak: true,\n _strengthenOnPublish: {\n _type: sourceDocument._type,\n _weak: false,\n },\n },\n },\n ],\n translationHistory: [],\n })) as TranslationMetadataDocument\n\n return newDoc\n } catch (error) {\n console.error(sourceDocument._id, 'Error creating translation metadata:', error)\n throw error\n }\n}\n","import defaults from 'lodash.defaults'\nimport type { Dispatch } from 'react'\nimport type { SetTranslationJobStatusAction, TranslationAction, TranslationJob } from '../types'\n\nexport const setJobStatus = (\n dispatch: Dispatch<TranslationAction>,\n _id: string,\n language: string,\n status: TranslationJob['status'],\n payload?: Partial<SetTranslationJobStatusAction['payload']>,\n) => {\n dispatch({\n type: 'SET_TRANSLATION_JOB_STATUS',\n payload: defaults(payload, {\n _id,\n language,\n status,\n }),\n })\n}\n","import type { SanityPatchMutation } from '@sanity/diff-patch'\nimport type { Dispatch } from 'react'\nimport type { SanityClient, SanityDocument } from 'sanity'\nimport type { TranslationAction } from '../types'\nimport { setJobStatus } from './setJobStatus'\n\ninterface TranslateDocumentInPlaceParams {\n client: SanityClient\n schemaId: string\n dispatch: Dispatch<TranslationAction>\n sourceDocument: SanityDocument\n languageFieldName: string\n targetLanguage: string\n targetId: string\n patch: Array<SanityPatchMutation>\n}\n\nexport const translateDocumentInPlace = async ({\n client,\n schemaId,\n dispatch,\n sourceDocument,\n languageFieldName,\n targetLanguage,\n targetId,\n patch,\n}: TranslateDocumentInPlaceParams) => {\n try {\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'translating')\n\n const updatedDocument = await client.agent.action.translate({\n schemaId,\n documentId: targetId,\n toLanguage: {\n title: targetLanguage,\n id: targetLanguage,\n },\n fromLanguage: {\n title: sourceDocument[languageFieldName] as string,\n id: sourceDocument[languageFieldName] as string,\n },\n languageFieldPath: [languageFieldName],\n styleGuide: `\n\t\t\t **IMPORTANT:** Much of this document is already translated into the target language. The original version of this document in the source language\n\t\t\t\twas updated. The following patch instruction shows precisely how the source document was edited: $patchInstruction. Your job is to update this\n\t\t\t translation to including matching changes.\n\t\t\t\t`,\n styleGuideParams: {\n patchInstruction: JSON.stringify(patch, null, 2),\n },\n })\n\n return updatedDocument as SanityDocument\n } catch (error) {\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'error')\n console.error('Error translating document:', error)\n }\n}\n","import type { TranslatableDocument } from '../types'\n\ninterface AssembleLanguageSpecsParams {\n sourceDocument: TranslatableDocument\n languageFieldName: string\n targetLanguage: string\n}\n\nexport const assembleLanguageSpecs = ({\n sourceDocument,\n languageFieldName,\n targetLanguage,\n}: AssembleLanguageSpecsParams): {\n toLanguage: { id: string; title: string }\n fromLanguage: { id: string; title: string }\n} => {\n const sourceLanugageId = sourceDocument[languageFieldName] as string | undefined\n\n if (!sourceLanugageId) {\n throw new Error('[assembleLanguages] Source language ID is missing')\n }\n\n return {\n fromLanguage: {\n id: sourceLanugageId,\n title: sourceLanugageId,\n },\n toLanguage: {\n id: targetLanguage,\n title: targetLanguage,\n },\n }\n}\n","import type { Dispatch } from 'react'\nimport type { SanityClient, SanityDocument } from 'sanity'\nimport { UPDATE_EXISTING_TRANSLATION_PROMPT } from '../consts'\nimport type { TranslatableDocument, TranslationAction } from '../types'\nimport { assembleLanguageSpecs } from './assembleLanguageSpecs'\nimport type { determineTranslationTarget } from './determineTranslationTarget'\nimport { devLog } from './devLog'\nimport type { FetchTranslationPromptsResult } from './fetchTranslationPrompts'\nimport { setJobStatus } from './setJobStatus'\nimport { draftId, undraftId } from './undraftId'\n\ninterface TranslateEntireDocumentOptions {\n dispatch: Dispatch<TranslationAction>\n client: SanityClient\n schemaId: string\n sourceDocument: TranslatableDocument\n targetLanguage: string\n languageFieldName: string\n translationTarget: ReturnType<typeof determineTranslationTarget>\n translationPrompts: FetchTranslationPromptsResult\n}\n\nexport const translateEntireDocument = async ({\n dispatch,\n client,\n schemaId,\n sourceDocument,\n targetLanguage,\n languageFieldName,\n translationTarget,\n translationPrompts,\n}: TranslateEntireDocumentOptions) => {\n const logContext = {\n documentId: sourceDocument._id,\n targetLanguage,\n schemaId,\n operation: translationTarget.operation,\n targetId: translationTarget._id,\n }\n\n devLog.group('translateEntireDocument', logContext)\n devLog.time('translateEntireDocument')\n\n try {\n // Assemble specs to tell the Sanity agent how to translate the document\n const { toLanguage, fromLanguage } = assembleLanguageSpecs({\n sourceDocument,\n languageFieldName,\n targetLanguage,\n })\n\n devLog.debug('Language specs assembled', {\n ...logContext,\n toLanguage,\n fromLanguage,\n })\n\n let extantTranslation = ''\n if (translationTarget._id) {\n devLog.debug('Checking for existing translation', {\n ...logContext,\n targetId: translationTarget._id,\n })\n\n extantTranslation = await client\n .withConfig({\n perspective: 'raw',\n })\n .fetch(`*[_id in $ids] | order((_id match \"drafts*\") desc)[0]._id`, {\n ids: [undraftId(translationTarget._id), draftId(translationTarget._id)],\n })\n\n devLog.info('Extant translation found - will preserve existing content where possible', {\n ...logContext,\n hasExtantTranslation: !!extantTranslation,\n })\n }\n\n // Ask the Sanity agent to translate the document\n devLog.info('Starting Sanity agent translation', logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'translating')\n\n const styleGuide = [\n translationPrompts.globalPrompt,\n translationPrompts.localeInstructions[targetLanguage]?.prompt,\n translationPrompts.localeInstructions[targetLanguage]?.glossaryTerms,\n extantTranslation ? UPDATE_EXISTING_TRANSLATION_PROMPT : null,\n ]\n .filter(Boolean)\n .join('\\n\\n')\n\n devLog.info('Style guide generated', {\n ...logContext,\n styleGuide,\n })\n\n const newDocument = (await client.agent.action.translate({\n schemaId,\n toLanguage,\n fromLanguage,\n documentId: sourceDocument._id,\n targetDocument: translationTarget,\n languageFieldPath: [languageFieldName],\n styleGuide,\n styleGuideParams: {\n extantTranslation,\n },\n protectedPhrases: translationPrompts.protectedPhrases || [],\n conditionalPaths: {\n defaultHidden: false,\n defaultReadOnly: false,\n },\n })) as SanityDocument\n\n devLog.info('Document translation completed', {\n ...logContext,\n newDocumentId: newDocument._id,\n newDocumentRev: newDocument._rev,\n })\n\n devLog.timeEnd('translateEntireDocument')\n devLog.groupEnd()\n return newDocument\n } catch (error) {\n devLog.error(\n 'translateEntireDocument failed',\n error instanceof Error ? error : new Error(String(error)),\n logContext,\n )\n devLog.timeEnd('translateEntireDocument')\n devLog.groupEnd()\n throw error\n }\n}\n","import type { SanityClient, SanityDocument } from 'sanity'\nimport type { TranslationMetadataDocument } from '../types'\nimport { undraftId } from './undraftId'\n\ninterface UpdateTranslationMetadataParams {\n client: SanityClient\n sourceDocument: SanityDocument\n sourceLanguage: string\n newDocument: SanityDocument\n targetLanguage: string\n translationMetadata: TranslationMetadataDocument\n isNewTranslation: boolean\n}\n\nexport const updateTranslationMetadata = async ({\n client,\n targetLanguage,\n sourceDocument,\n sourceLanguage,\n newDocument,\n translationMetadata,\n isNewTranslation,\n}: UpdateTranslationMetadataParams) => {\n try {\n const refToNewTranslation: TranslationMetadataDocument['translations'][number] = {\n _key: targetLanguage,\n _type: 'internationalizedArrayReferenceValue',\n value: {\n _type: 'reference',\n _ref: undraftId(newDocument._id),\n _weak: true,\n _strengthenOnPublish: {\n _type: 'reference',\n _weak: false,\n },\n },\n }\n\n const newTranslationHistory: TranslationMetadataDocument['translationHistory'][number] = {\n _key: targetLanguage,\n language: targetLanguage,\n sourceId: undraftId(sourceDocument._id),\n sourceRev: sourceDocument._rev,\n sourceLanguage,\n sourceSnapshot: JSON.stringify(sourceDocument),\n targetId: newDocument._id,\n targetRev: newDocument._rev,\n targetSnapshot: JSON.stringify(newDocument),\n }\n\n const translationPatch = client\n .patch(translationMetadata._id)\n // If there is no value set for `translations`, set it to an empty array\n .setIfMissing({ translations: [] })\n\n if (isNewTranslation) {\n await translationPatch.insert('after', 'translations[-1]', [refToNewTranslation]).commit()\n } else {\n await translationPatch\n .insert('replace', `translations[_key == \"${targetLanguage}\"]`, [refToNewTranslation])\n .commit()\n }\n\n const historyPatch = client.patch(translationMetadata._id).setIfMissing({ translationHistory: [] })\n const translationHistoryExists = !!translationMetadata.translationHistory?.some(\n (history) => history.language === targetLanguage,\n )\n\n if (!translationHistoryExists) {\n await historyPatch.insert('after', 'translationHistory[-1]', [newTranslationHistory]).commit()\n } else {\n await historyPatch\n .insert('replace', `translationHistory[_key == \"${targetLanguage}\"]`, [newTranslationHistory])\n .commit()\n }\n } catch (error) {\n console.error('Error updating translation metadata:', error)\n throw error\n }\n}\n","import { diffPatch } from '@sanity/diff-patch'\nimport type { Dispatch } from 'react'\nimport type { SanityClient, SanityDocument } from 'sanity'\nimport type { PluginConfig, TranslatableDocument, TranslationAction, TranslationMetadataDocument } from '../types'\nimport { determineTranslationTarget } from './determineTranslationTarget'\nimport { devLog } from './devLog'\nimport type { FetchTranslationPromptsResult } from './fetchTranslationPrompts'\nimport { getTranslationMetadata } from './getTranslationMetadata'\nimport { setJobStatus } from './setJobStatus'\nimport { translateDocumentInPlace } from './translateDocumentInPlace'\nimport { translateEntireDocument } from './translateEntireDocument'\nimport { draftId, undraftId } from './undraftId'\nimport { updateTranslationMetadata } from './updateTranslationMetadata'\n\ninterface TranslateDocumentParams {\n dispatch: Dispatch<TranslationAction>\n client: SanityClient\n sourceDocument: TranslatableDocument\n targetLanguage: PluginConfig['supportedLanguages'][number]['id']\n languageFieldName: PluginConfig['languageFieldName']\n shouldOverwriteFreshTranslations: boolean\n schemaId: string\n shouldTranslateDiffs: boolean\n translationPrompts: FetchTranslationPromptsResult\n}\n\nexport const translateDocument = async ({\n dispatch,\n client,\n sourceDocument,\n targetLanguage,\n languageFieldName,\n shouldOverwriteFreshTranslations,\n schemaId,\n shouldTranslateDiffs,\n translationPrompts,\n}: TranslateDocumentParams) => {\n const logContext = {\n documentId: sourceDocument._id,\n targetLanguage,\n schemaId,\n shouldTranslateDiffs,\n shouldOverwriteFreshTranslations,\n }\n\n devLog.group('translateDocument', logContext)\n devLog.time('translateDocument')\n\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'preparing_translation')\n\n try {\n // Confirm that source document has a language\n const sourceLanguage = sourceDocument[languageFieldName] as string | undefined\n\n devLog.debug('Checking source document language', {\n ...logContext,\n sourceLanguage,\n languageFieldName,\n })\n\n if (!sourceLanguage) {\n const error = `Source document ${sourceDocument._id} does not have a language`\n devLog.error(error, undefined, logContext)\n throw new Error(error)\n }\n\n // Get the translation metadata for the document, creating it if necessary\n devLog.debug('Getting translation metadata', logContext)\n const translationMetadata = await getTranslationMetadata({\n client,\n sourceDocument,\n sourceLanguage,\n })\n\n const isAlreadyFreshTranslation =\n translationMetadata.translationHistory?.some(\n (history) => history.language === targetLanguage && history.sourceRev === sourceDocument._rev,\n ) ?? false\n\n devLog.debug('Checking if translation is already fresh', {\n ...logContext,\n isAlreadyFreshTranslation,\n currentRev: sourceDocument._rev,\n })\n\n if (!shouldOverwriteFreshTranslations && isAlreadyFreshTranslation) {\n devLog.info('Skipping fresh translation', logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'skipped', {\n targetId: translationMetadata.translations.find((t) => t._key === targetLanguage)?.value._ref,\n })\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n return\n }\n\n // Determine if we need to update an existing translation or create a new document\n const translationTarget = determineTranslationTarget({\n translationMetadata,\n targetLanguage,\n })\n const isNewTranslation = translationTarget.operation === 'create'\n\n devLog.debug('Translation target determined', {\n ...logContext,\n operation: translationTarget.operation,\n isNewTranslation,\n })\n\n let newDocument: SanityDocument | undefined\n\n // DIFFS TRANSLATION\n if (!isNewTranslation && shouldTranslateDiffs) {\n devLog.info('Starting diff-based translation', logContext)\n\n // Patch the changes that have been made to the source document into the translation target\n // This will result in the target document temporarily containing content in multiple languages\n const { currentTargetId, patch } = await patchTranslationTarget({\n client,\n currentSourceDocument: sourceDocument,\n sourceLanguage,\n translationMetadata,\n targetLanguage,\n })\n\n if (!currentTargetId) {\n devLog.warn('No target ID found for diff translation', logContext)\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n return\n }\n\n devLog.debug('Patching translation target', {\n ...logContext,\n currentTargetId,\n hasPatch: !!patch,\n })\n\n // Ask the Sanity agent to complete the translation of the target document\n newDocument = await translateDocumentInPlace({\n client,\n schemaId,\n dispatch,\n sourceDocument,\n languageFieldName,\n targetLanguage,\n targetId: currentTargetId,\n patch,\n })\n } else {\n // TRANSLATE ENTIRE DOCUMENT\n devLog.info('Starting full document translation', {\n ...logContext,\n translationTarget: translationTarget.operation,\n })\n\n newDocument = await translateEntireDocument({\n dispatch,\n client,\n schemaId,\n sourceDocument,\n targetLanguage,\n languageFieldName,\n translationTarget,\n translationPrompts,\n })\n }\n\n if (!newDocument) {\n devLog.error('Failed to create translation document', undefined, logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'error')\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n throw new Error('Failed to create translation document')\n }\n\n devLog.debug('Translation document created', {\n ...logContext,\n newDocumentId: newDocument._id,\n })\n\n // UPDATE TRANSLATION METADATA\n devLog.debug('Updating translation metadata', logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'updating_metadata', {\n targetId: newDocument._id,\n })\n\n await updateTranslationMetadata({\n client,\n sourceDocument,\n sourceLanguage,\n newDocument,\n targetLanguage,\n translationMetadata,\n isNewTranslation,\n })\n\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'completed')\n devLog.info('Translation completed successfully', {\n ...logContext,\n newDocumentId: newDocument._id,\n })\n\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n return newDocument._id\n } catch (error) {\n devLog.error('Translation failed', error instanceof Error ? error : new Error(String(error)), logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'error')\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n throw error\n }\n}\n\ninterface PatchTranslationTargetParams {\n client: SanityClient\n currentSourceDocument: SanityDocument\n sourceLanguage: string\n translationMetadata: TranslationMetadataDocument\n targetLanguage: string\n}\n\nconst patchTranslationTarget = async ({\n client,\n currentSourceDocument,\n translationMetadata,\n targetLanguage,\n}: PatchTranslationTargetParams) => {\n const sourceSnapshotString = translationMetadata.translationHistory.find(\n (h) => undraftId(h.sourceId) === undraftId(currentSourceDocument._id),\n )?.sourceSnapshot\n\n if (!sourceSnapshotString) {\n return {}\n }\n\n const sourceSnapshot = JSON.parse(sourceSnapshotString)\n const targetId = translationMetadata.translations.find((t) => t._key === targetLanguage)?.value._ref\n\n if (!targetId) {\n return {}\n }\n\n const currentTargetId = await client.fetch<string | null>(\n '*[_id in $ids] | order((_id match \"drafts*\") desc)[0]._id',\n { ids: [undraftId(targetId), draftId(targetId)] },\n )\n\n if (!currentTargetId) {\n console.log(`No document found for ${targetId}`)\n return {}\n }\n\n // create diff patch between the previously translated version of the source and the current version of the source\n const patch = diffPatch(sourceSnapshot, currentSourceDocument, {\n id: draftId(currentTargetId),\n })\n\n return { currentTargetId, patch }\n}\n","import type { Dispatch } from 'react'\nimport type { SanityClient } from 'sanity'\nimport type { TranslatableDocument, TranslationAction } from '../types'\nimport type { AssembleReferencesResult } from './assembleReferences'\nimport { devLog } from './devLog'\nimport { fetchTranslationPrompts } from './fetchTranslationPrompts'\nimport { localizeReferences } from './localizeReferences'\nimport { Semaphore } from './Semaphore'\nimport { setupTranslationJobStatuses } from './setupTranslationJobStatuses'\nimport { translateDocument } from './translateDocument'\n\ninterface TranslateDocumentsParams {\n sourceDocument: TranslatableDocument\n targetLanguages: Array<string>\n client: SanityClient\n dispatch: Dispatch<TranslationAction>\n languageFieldName: string\n shouldOverwriteFreshTranslations: boolean\n schemaId: string\n references: AssembleReferencesResult\n maxConcurrentTranslationJobs?: number\n maxReferenceDepth?: number\n shouldTranslateDiffs: boolean\n}\n\nconst translationSemaphore = new Semaphore(2)\n\nexport const translateDocumentSet = async ({\n client,\n sourceDocument,\n targetLanguages,\n dispatch,\n languageFieldName,\n shouldOverwriteFreshTranslations,\n schemaId,\n references = [],\n maxConcurrentTranslationJobs,\n shouldTranslateDiffs,\n}: TranslateDocumentsParams) => {\n const logContext = {\n documentId: sourceDocument._id,\n targetLanguages,\n referencesCount: references.length,\n maxConcurrentJobs: maxConcurrentTranslationJobs,\n shouldTranslateDiffs,\n shouldOverwriteFreshTranslations,\n }\n\n devLog.group('translateDocumentSet', logContext)\n devLog.time('translateDocumentSet')\n\n try {\n const sourceLanguage = sourceDocument[languageFieldName] as string\n\n if (!sourceLanguage) {\n devLog.error('Source language not found')\n throw new Error('Source language not found')\n }\n\n // If the config specifies a max concurrent translation jobs, update the semaphore\n if (maxConcurrentTranslationJobs) {\n devLog.debug('Updating translation semaphore permits', {\n ...logContext,\n newPermits: maxConcurrentTranslationJobs,\n })\n translationSemaphore.updatePermits(maxConcurrentTranslationJobs)\n }\n\n devLog.info('Starting document set translation', logContext)\n dispatch({\n type: 'SET_OVERALL_STATUS',\n payload: 'translating',\n })\n\n const sourceDocuments = [\n {\n _id: sourceDocument._id,\n _type: sourceDocument._type,\n // TODO: Handle this properly\n title: (sourceDocument.name || sourceDocument.title) as string | undefined,\n },\n ...references,\n ]\n\n const sourceDocumentIds = sourceDocuments.map((doc) => doc._id)\n const targetDocumentIds: Array<string> = []\n\n devLog.debug('Prepared document set for translation', {\n ...logContext,\n sourceDocumentIds: sourceDocumentIds.length,\n totalTranslationJobs: sourceDocumentIds.length * targetLanguages.length,\n })\n\n // Assemble prompts for translation task style guides\n const translationPrompts = await fetchTranslationPrompts({\n client,\n sourceLanguage,\n targetLanguages,\n })\n\n devLog.info('Translation prompts', translationPrompts)\n\n // Dispatch new job statuses for each document\n setupTranslationJobStatuses(dispatch, sourceDocuments, targetLanguages)\n\n // Create translation tasks for all documents and all languages\n const translationTasks = sourceDocumentIds.flatMap((documentId) =>\n targetLanguages.map(async (targetLanguage) => {\n await translationSemaphore.withPermit(async () => {\n // Fetch the document\n const document = await client\n .withConfig({\n // This enables us to detect documents that might be stale due to unpublished changes\n perspective: 'raw',\n })\n .fetch<TranslatableDocument>('*[_id == $id][0]', {\n id: documentId,\n })\n if (document) {\n const targetDocumentId = await translateDocument({\n dispatch,\n client,\n sourceDocument: document,\n targetLanguage,\n languageFieldName,\n shouldOverwriteFreshTranslations,\n schemaId,\n shouldTranslateDiffs,\n translationPrompts,\n })\n\n if (targetDocumentId) {\n targetDocumentIds.push(targetDocumentId)\n }\n }\n })\n }),\n )\n\n await Promise.all(translationTasks)\n\n devLog.info('All translation tasks completed', {\n ...logContext,\n targetDocumentIds: targetDocumentIds.length,\n })\n\n dispatch({\n type: 'SET_OVERALL_STATUS',\n payload: 'linking_references',\n })\n\n devLog.debug('Starting reference localization', {\n ...logContext,\n documentsToLocalize: targetDocumentIds.length,\n })\n\n await Promise.all(\n targetDocumentIds.map(async (documentId) => {\n await localizeReferences({\n client,\n documentId,\n languageFieldName,\n })\n }),\n )\n\n devLog.info('Document set translation completed successfully', logContext)\n devLog.timeEnd('translateDocumentSet')\n devLog.groupEnd()\n\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'completed' })\n } catch (error) {\n devLog.error('translateDocumentSet failed', error instanceof Error ? error : new Error(String(error)), logContext)\n devLog.timeEnd('translateDocumentSet')\n devLog.groupEnd()\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'error' })\n return Promise.reject(error)\n }\n}\n","import { Button, Flex } from '@sanity/ui'\nimport { useClient } from 'sanity'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { translateDocumentSet } from '../utils/translateDocumentSet'\n\ninterface ActionButtonBarProps {\n setIsDialogOpen: (isOpen: boolean) => void\n}\n\nexport const ActionButtonBar = ({ setIsDialogOpen }: ActionButtonBarProps) => {\n const {\n document,\n config,\n overallStatus,\n dispatch,\n references,\n selectedTargetLanguages,\n shouldOverwriteFreshTranslations,\n shouldTranslateDiffs,\n } = useTranslationContext()\n const client = useClient({ apiVersion: 'vX' })\n\n const handleTranslate = () => {\n translateDocumentSet({\n sourceDocument: document,\n targetLanguages: selectedTargetLanguages,\n client,\n dispatch,\n languageFieldName: config.languageFieldName,\n schemaId: config.schemaId,\n references,\n shouldOverwriteFreshTranslations,\n maxConcurrentTranslationJobs: config.maxConcurrentTranslationJobs,\n maxReferenceDepth: config.maxReferenceDepth,\n shouldTranslateDiffs,\n })\n }\n\n const handleSelectAll = () => {\n dispatch({\n type: 'SET_SELECTED_TARGET_LANGUAGES',\n payload: config.supportedLanguages.map((lang) => lang.id).filter((id) => id !== document.language),\n })\n }\n\n const handleSelectNone = () => {\n dispatch({\n type: 'SET_SELECTED_TARGET_LANGUAGES',\n payload: [],\n })\n }\n\n return (\n <Flex justify=\"space-between\" gap={2}>\n <Flex justify=\"flex-start\" gap={2}>\n <Button mode=\"ghost\" size={2} onClick={handleSelectAll}>\n Select All\n </Button>\n <Button mode=\"ghost\" size={2} onClick={handleSelectNone}>\n Select None\n </Button>\n </Flex>\n <Flex justify=\"flex-end\" gap={2}>\n <Button onClick={() => setIsDialogOpen(false)} mode=\"ghost\" size={2}>\n Cancel\n </Button>\n <Button\n mode=\"ghost\"\n tone=\"positive\"\n size={2}\n onClick={handleTranslate}\n disabled={selectedTargetLanguages.length === 0 || !['idle', 'completed'].includes(overallStatus)}\n >\n Translate\n </Button>\n </Flex>\n </Flex>\n )\n}\n","import { Badge, Button, Checkbox, Flex, Inline, Spinner, Text } from '@sanity/ui'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport type { PluginConfig } from '../types'\n\ninterface LanguageCheckboxProps {\n lang: PluginConfig['supportedLanguages'][number]\n isLoading: boolean\n}\n\nexport const LanguageCheckbox = ({ lang, isLoading }: LanguageCheckboxProps) => {\n const { document, dispatch, selectedTargetLanguages, translationMetadata } = useTranslationContext()\n const isDisabled = lang.id === document.language\n const isChecked = selectedTargetLanguages.includes(lang.id)\n const hasTranslation = translationMetadata?.translations?.some((translation) => translation._key === lang.id)\n const isStale =\n hasTranslation &&\n translationMetadata?.translationHistory?.some(\n (history) => history.language === lang.id && history.sourceRev !== document._rev,\n )\n\n const handleChange = () => {\n if (isDisabled) return\n\n const updatedLanguages = isChecked\n ? selectedTargetLanguages.filter((langId) => langId !== lang.id)\n : [...selectedTargetLanguages, lang.id]\n\n dispatch({\n type: 'SET_SELECTED_TARGET_LANGUAGES',\n payload: updatedLanguages,\n })\n }\n\n if (isLoading) {\n return (\n <Button type=\"button\" mode=\"bleed\" size={2} onClick={handleChange} disabled muted>\n <Flex align=\"center\" justify=\"center\" paddingY={3}>\n <Spinner size={1} />\n </Flex>\n </Button>\n )\n }\n\n return (\n <Button\n type=\"button\"\n mode={isChecked ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleChange}\n disabled={isDisabled}\n tone={isChecked ? 'primary' : 'default'}\n muted\n >\n <Flex align=\"center\" gap={2} style={{ cursor: 'pointer' }}>\n <Inline space={3}>\n <Checkbox checked={isChecked} onChange={handleChange} label={lang.title} disabled={isDisabled} />\n <Flex direction=\"column\" gap={3}>\n <Text>{lang.title}</Text>\n {!isDisabled ? (\n <Text size={1} muted>\n {hasTranslation && !isDisabled ? 'Already translated' : 'Not translated'}\n </Text>\n ) : (\n <Text size={1} muted>\n The current language\n </Text>\n )}\n </Flex>\n </Inline>\n {!isDisabled && hasTranslation && (\n <Flex flex={1} justify=\"flex-end\">\n <Badge tone={isStale ? 'caution' : 'positive'} size={3} muted>\n {isStale ? 'Stale' : 'Fresh'}\n </Badge>\n </Flex>\n )}\n </Flex>\n </Button>\n )\n}\n","import { Card, Grid } from '@sanity/ui'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { useTranslationMetadata } from '../hooks/useTranslationMetadata'\nimport { LanguageCheckbox } from './LanguageCheckbox'\n\nexport const LanguageSelectionPanel = () => {\n // Get the configuration from the context\n const { document, config } = useTranslationContext()\n\n const { loading } = useTranslationMetadata({\n documentId: document._id,\n })\n\n return (\n <Card padding={4} muted border>\n <Grid columns={[1, 2]} gap={3}>\n {config?.supportedLanguages.map((lang) => (\n <LanguageCheckbox key={lang.id} lang={lang} isLoading={loading} />\n ))}\n </Grid>\n </Card>\n )\n}\n","import type { SanityClient, SanityDocument } from 'sanity'\nimport type { TranslatableDocument } from '../types'\nimport { findKeyValues, type RecursiveSearchable } from './findKeyValues/findKeyValues'\n\ninterface AssembleReferencesParams {\n client: SanityClient\n sourceDocument: SanityDocument\n maxReferenceDepth: number\n translatableSchemaTypes?: Array<string>\n}\n\nexport type AssembleReferencesResult = Array<{\n _id: SanityDocument['_id']\n _type: SanityDocument['_type']\n title?: string\n}>\n\n// Sanity documents are objects of arbitrary shape, which can\n// contain references to other documents. References are always\n// represented as a `_ref` key with a value of the referenced document's\n// `_id`. This function takes a Sanity document, appends all `_ref` keys\n// within it to an array, then fetches the references documents and repeats\n// the process until the maximum reference depth is reached.\n\nexport const assembleReferences = async ({\n client,\n sourceDocument,\n maxReferenceDepth,\n translatableSchemaTypes = [],\n}: AssembleReferencesParams): Promise<AssembleReferencesResult> => {\n // Input validation\n if (!client) {\n throw new Error('assembleReferences: client is required')\n }\n\n if (!sourceDocument || !sourceDocument._id) {\n throw new Error('assembleReferences: sourceDocument with _id is required')\n }\n\n if (typeof maxReferenceDepth !== 'number' || maxReferenceDepth < 0) {\n throw new Error('assembleReferences: maxReferenceDepth must be a non-negative number')\n }\n\n const references = new Set<string>()\n const documentCache = new Map<string, TranslatableDocument | null>()\n const errors: Array<{ refId: string; error: Error }> = []\n\n let currentDepthDocuments = [sourceDocument]\n\n for (let depth = 0; depth < maxReferenceDepth && currentDepthDocuments.length > 0; depth++) {\n // Collect all reference IDs from current depth documents\n const allRefIds = new Set<string>()\n\n for (const document of currentDepthDocuments) {\n try {\n const refResults = findKeyValues<string>(document as RecursiveSearchable, '_ref')\n for (const result of refResults) {\n const refId = result.value\n if (typeof refId === 'string' && refId.length > 0 && !references.has(refId) && !documentCache.has(refId)) {\n allRefIds.add(refId)\n }\n }\n } catch (error) {\n console.error('assembleReferences: Error finding references in document:', error)\n }\n }\n\n if (allRefIds.size === 0) {\n break\n }\n\n // Batch fetch all references for this depth level\n const refIdArray = Array.from(allRefIds)\n try {\n const batchResults = await client.fetch<TranslatableDocument[]>('*[_id in $ids]', { ids: refIdArray })\n\n // Create a map of fetched documents by ID\n const fetchedDocuments = new Map<string, TranslatableDocument>()\n for (const doc of batchResults) {\n fetchedDocuments.set(doc._id, doc)\n }\n\n // Process each reference ID\n const nextDepthDocuments: TranslatableDocument[] = []\n\n for (const refId of refIdArray) {\n const fetchedDoc = fetchedDocuments.get(refId)\n\n if (fetchedDoc) {\n // Skip non-translatable documents\n if (translatableSchemaTypes.length > 0 && !translatableSchemaTypes.includes(fetchedDoc._type)) {\n documentCache.set(refId, null)\n continue\n }\n\n documentCache.set(refId, fetchedDoc)\n references.add(refId)\n nextDepthDocuments.push(fetchedDoc)\n } else {\n // Document not found\n documentCache.set(refId, null)\n console.warn(`assembleReferences: Document with _id \"${refId}\" not found`)\n }\n }\n\n currentDepthDocuments = nextDepthDocuments\n } catch (fetchError) {\n // Log the error but continue processing\n const error = fetchError instanceof Error ? fetchError : new Error(String(fetchError))\n errors.push({ refId: `batch(${refIdArray.join(',')})`, error })\n console.error('assembleReferences: Failed to batch fetch documents:', error.message)\n break\n }\n }\n\n // Log summary of errors if any occurred\n if (errors.length > 0) {\n console.warn(`assembleReferences: Encountered ${errors.length} error(s) while fetching references`)\n }\n\n // Convert the cached documents to the expected result format\n const result: AssembleReferencesResult = []\n for (const refId of references) {\n const cachedDoc = documentCache.get(refId)\n if (cachedDoc) {\n result.push({\n _id: cachedDoc._id,\n _type: cachedDoc._type,\n title: (cachedDoc.name || cachedDoc.title) as string | undefined,\n })\n }\n }\n\n return result\n}\n","import { Button, Checkbox, Flex, Inline, Select, Stack, Text } from '@sanity/ui'\nimport { useEffect, useState } from 'react'\nimport { useClient } from 'sanity'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { assembleReferences } from '../utils/assembleReferences'\n\nexport const ReferenceConfigPanel = () => {\n const { dispatch, document, shouldTranslateReferences, maxReferenceDepth, config, references } =\n useTranslationContext()\n const client = useClient({ apiVersion: 'vX' })\n const [isLoadingReferences, setIsLoadingReferences] = useState(false)\n const maxDepth = config.maxReferenceDepth || 3\n\n useEffect(() => {\n const updateReferences = async () => {\n setIsLoadingReferences(true)\n\n if (!shouldTranslateReferences) {\n dispatch({\n type: 'SET_REFERENCES',\n payload: [],\n })\n return\n }\n\n const newReferences = await assembleReferences({\n client,\n sourceDocument: document,\n maxReferenceDepth,\n translatableSchemaTypes: config.translatableSchemaTypes,\n })\n dispatch({\n type: 'SET_REFERENCES',\n payload: newReferences,\n })\n\n setIsLoadingReferences(false)\n }\n\n updateReferences()\n }, [document, client, dispatch, shouldTranslateReferences, maxReferenceDepth, config.translatableSchemaTypes])\n\n const handleMaxReferenceDepthChange = async (event: React.ChangeEvent<HTMLSelectElement>) => {\n dispatch({\n type: 'SET_MAX_REFERENCE_DEPTH',\n payload: Number.parseInt(event.target.value),\n })\n }\n\n const handleShouldTranslateChange = () => {\n dispatch({\n type: 'SET_SHOULD_TRANSLATE_REFERENCES',\n payload: !shouldTranslateReferences,\n })\n }\n\n return (\n <Stack space={2}>\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n type=\"button\"\n mode={shouldTranslateReferences ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleShouldTranslateChange}\n tone={shouldTranslateReferences ? 'primary' : 'neutral'}\n >\n <Inline space={2}>\n <Checkbox\n checked={shouldTranslateReferences}\n onChange={handleShouldTranslateChange}\n label={shouldTranslateReferences ? 'Disable' : 'Enable'}\n />\n <Text>Translate References</Text>\n </Inline>\n </Button>\n {shouldTranslateReferences ? (\n <Inline space={2}>\n <Text>Max Depth:</Text>\n <Select\n disabled={!shouldTranslateReferences}\n placeholder=\"Depth\"\n onChange={handleMaxReferenceDepthChange}\n value={maxReferenceDepth.toString()}\n >\n {Array.from({ length: maxDepth }, (_, i) => i + 1).map((depth) => (\n <option key={depth} value={depth.toString()}>\n {depth}\n </option>\n ))}\n </Select>\n </Inline>\n ) : null}\n </Flex>\n {shouldTranslateReferences ? (\n <Flex padding={2} justify=\"flex-end\">\n <Text size={1} muted>\n {isLoadingReferences\n ? 'Loading references...'\n : references.length === 0\n ? 'No translatable references found.'\n : `${references.length} translatable references found.`}\n </Text>\n </Flex>\n ) : null}\n </Stack>\n )\n}\n","import { Badge, Button, Checkbox, Flex, Inline, Stack, Text } from '@sanity/ui'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { ReferenceConfigPanel } from './ReferenceConfigPanel'\n\nexport const WriteSettingsPanel = () => {\n const { dispatch, shouldOverwriteFreshTranslations, shouldTranslateDiffs } = useTranslationContext()\n\n const handleShouldOverwriteFreshTranslationsChange = () => {\n dispatch({\n type: 'SET_SHOULD_OVERWRITE_FRESH_TRANSLATIONS',\n payload: !shouldOverwriteFreshTranslations,\n })\n }\n\n const handleShouldTranslateDiffsChange = () => {\n dispatch({\n type: 'SET_SHOULD_TRANSLATE_DIFFS',\n payload: !shouldTranslateDiffs,\n })\n }\n\n return (\n <Stack space={2}>\n <ReferenceConfigPanel />\n {/* Overwrite fresh translations */}\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n type=\"button\"\n mode={shouldOverwriteFreshTranslations ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleShouldOverwriteFreshTranslationsChange}\n tone={shouldOverwriteFreshTranslations ? 'primary' : 'neutral'}\n >\n <Inline space={2}>\n <Checkbox\n checked={shouldOverwriteFreshTranslations}\n onChange={handleShouldOverwriteFreshTranslationsChange}\n label={shouldOverwriteFreshTranslations ? 'Disable' : 'Enable'}\n />\n <Stack space={2}>\n <Text>Overwrite Fresh Translations</Text>\n <Text size={1} muted>\n All existing translations will be overwritten even if they are fresh.\n </Text>\n </Stack>\n </Inline>\n </Button>\n </Flex>\n\n {/* Translate diffs */}\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n type=\"button\"\n mode={shouldTranslateDiffs ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleShouldTranslateDiffsChange}\n tone={shouldTranslateDiffs ? 'primary' : 'neutral'}\n >\n <Inline space={2}>\n <Checkbox\n checked={shouldTranslateDiffs}\n onChange={handleShouldOverwriteFreshTranslationsChange}\n label={shouldTranslateDiffs ? 'Disable' : 'Enable'}\n />\n <Stack space={3}>\n <Inline space={1}>\n <Text>Translate Diffs</Text>\n <Badge tone=\"caution\">Experimental</Badge>\n </Inline>\n <Text size={1} muted>\n Only re-translate content that has changed in the source document.\n </Text>\n </Stack>\n </Inline>\n </Button>\n </Flex>\n </Stack>\n )\n}\n","import { Card, Label, Stack } from '@sanity/ui'\nimport type { FC } from 'react'\nimport { ActionButtonBar } from './ActionButtonBar'\nimport { LanguageSelectionPanel } from './LanguageSelectionPanel'\nimport { WriteSettingsPanel } from './WriteSettingsPanel'\n\ninterface TranslationConfigViewProps {\n setIsDialogOpen: (isOpen: boolean) => void\n}\n\nexport const TranslationConfigView: FC<TranslationConfigViewProps> = ({ setIsDialogOpen }) => {\n return (\n <Stack space={4}>\n <Stack space={2}>\n <Label>Languages</Label>\n <LanguageSelectionPanel />\n </Stack>\n\n <Stack space={2}>\n <Label>Settings</Label>\n <Card padding={4} border muted>\n <WriteSettingsPanel />\n </Card>\n </Stack>\n <ActionButtonBar setIsDialogOpen={setIsDialogOpen} />\n </Stack>\n )\n}\n","import { ArrowRightIcon, CheckmarkIcon, CircleIcon, PanelRightIcon } from '@sanity/icons'\nimport { Badge, Box, Button, Card, Code, Flex, Heading, Inline, Label, Spinner, Stack, Text, Tooltip } from '@sanity/ui'\nimport { useMemo } from 'react'\nimport { useOpenInNewPane } from 'sanity-plugin-utils'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\n\nconst TERMINAL_STATUSES = ['completed', 'skipped', 'error']\n\nexport const TranslationStatusPanel = () => {\n const { overallStatus, translationJobs } = useTranslationContext()\n\n const headline = useMemo(\n () => (overallStatus === 'completed' ? 'Translation completed' : 'Translation in progress'),\n [overallStatus],\n )\n\n const jobs = useMemo(() => Array.from(translationJobs.values()), [translationJobs])\n\n return (\n <Stack space={4}>\n <Heading size={2}>{headline}</Heading>\n <ProgressBar progress={jobs.filter((job) => TERMINAL_STATUSES.includes(job.status)).length} max={jobs.length} />\n <Stack space={3}>\n <Label>Translations</Label>\n <Card padding={2} tone=\"transparent\">\n <Stack space={2}>\n <ul style={{ listStyleType: 'none', paddingInlineStart: '0' }}>\n {jobs.map((job) => (\n <li key={job._id}>\n <Box padding={3}>\n <Flex justify=\"space-between\" align=\"center\">\n <Inline space={2}>\n <Flex align=\"center\" justify=\"center\" style={{ width: '24px', height: '24px' }}>\n {['completed', 'skipped'].includes(job.status) ? (\n <CheckmarkIcon fontSize={24} />\n ) : job.status === 'queued' ? (\n <CircleIcon fontSize={24} />\n ) : (\n <Spinner />\n )}\n </Flex>\n <Stack space={3}>\n <Inline space={2}>\n <Text size={1} weight=\"semibold\">\n {job.title || 'Untitled Document'}\n </Text>\n <ArrowRightIcon fontSize={18} />\n <Code size={1}>{job.language}</Code>\n </Inline>\n <Code size={1}>\n {job._type} — {job._id.slice(-6)}\n </Code>\n </Stack>\n </Inline>\n <Flex gap={2} align=\"center\">\n {job.status === 'skipped' ? <SkippedBadge /> : null}\n {job.targetId ? (\n <TranslationOpenerButton\n target={{\n _id: job.targetId,\n _type: job._type as string,\n }}\n />\n ) : null}\n </Flex>\n </Flex>\n </Box>\n </li>\n ))}\n </ul>\n </Stack>\n </Card>\n </Stack>\n </Stack>\n )\n}\n\nconst ProgressBar = ({ progress, max = 100 }: { progress: number; max?: number }) => {\n const percentage = Math.min((progress / max) * 100, 100)\n\n return (\n <Stack space={2}>\n <div\n style={{\n width: '100%',\n height: '8px',\n backgroundColor: 'var(--card-border-color)',\n borderRadius: '4px',\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n width: `${percentage}%`,\n height: '100%',\n backgroundColor: 'var(--card-accent-fg-color)',\n borderRadius: '4px',\n transition: 'width 0.3s ease-in-out',\n }}\n />\n </div>\n <Flex justify=\"space-between\" align=\"center\">\n <Text size={1} muted>\n {percentage.toFixed(0)}%\n </Text>\n <Text size={1} muted>\n {progress} / {max} jobs completed.\n </Text>\n </Flex>\n </Stack>\n )\n}\n\nconst TranslationOpenerButton = ({ target }: { target: { _id: string; _type: string } }) => {\n const openInNewPane = useOpenInNewPane(target._id, target._type)\n\n return <Button mode=\"bleed\" text=\"View\" iconRight={PanelRightIcon} onClick={() => openInNewPane()} />\n}\n\nconst SkippedBadge = () => (\n <Tooltip\n portal\n content={\n <Box padding={1}>\n <Text size={1} muted>\n There was already a fresh translation for this document and language.\n </Text>\n </Box>\n }\n >\n <Badge tone=\"neutral\">Skipped</Badge>\n </Tooltip>\n)\n","import type { FC } from 'react'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport type { OverallTranslationStatus } from '../types'\nimport { devLog } from '../utils/devLog'\nimport { TranslationConfigView } from './TranslationConfigPanel'\nimport { TranslationStatusPanel } from './TranslationStatusPanel'\n\ninterface TranslationDialogProps {\n setIsDialogOpen: (isOpen: boolean) => void\n}\n\nconst STATES_IN_WHICH_TO_SHOW_CONFIG: Array<OverallTranslationStatus> = ['fetching_metadata', 'idle']\n\nconst STATES_IN_WHICH_TO_SHOW_TRANSLATION_PROGRESS: Array<OverallTranslationStatus> = [\n 'translating',\n 'linking_references',\n 'completed',\n]\n\nconst STATES_IN_WHICH_TO_SHOW_ERROR: Array<OverallTranslationStatus> = ['error']\n\nconst _STATES_IN_WHICH_TO_SHOW_COMPLETE: Array<OverallTranslationStatus> = ['completed']\n\nexport const TranslationDialog: FC<TranslationDialogProps> = ({ setIsDialogOpen }) => {\n const { overallStatus, document } = useTranslationContext()\n\n devLog.debug('TranslationDialog rendered', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n\n if (STATES_IN_WHICH_TO_SHOW_CONFIG.includes(overallStatus)) {\n devLog.debug('Showing translation config view', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n return <TranslationConfigView setIsDialogOpen={setIsDialogOpen} />\n }\n\n if (STATES_IN_WHICH_TO_SHOW_TRANSLATION_PROGRESS.includes(overallStatus)) {\n devLog.debug('Showing translation progress panel', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n return <TranslationStatusPanel />\n }\n\n if (STATES_IN_WHICH_TO_SHOW_ERROR.includes(overallStatus)) {\n devLog.warn('Translation error state reached', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n return <div>Error occurred</div>\n }\n\n // if (STATES_IN_WHICH_TO_SHOW_COMPLETE.includes(overallStatus)) {\n // \treturn <div>Translation completed</div>;\n // }\n\n devLog.warn('Unhandled translation dialog state', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n\n return <div>Unhandled overall state</div>\n}\n","import { TranslateIcon } from '@sanity/icons'\nimport { useState } from 'react'\nimport type { DocumentActionDescription, DocumentActionProps } from 'sanity'\nimport { TranslationDialog } from './components/TranslationDialog'\nimport { TranslationContextProvider } from './hooks/useTranslationContext/TranslationContextProvider'\nimport type { PluginConfig, TranslatableDocument } from './types'\nimport { devLog } from './utils/devLog'\n\ninterface TranslateActionProps extends DocumentActionProps {\n config: PluginConfig\n}\n\nexport const getTranslateAction = (config: PluginConfig) => {\n return ({ draft, published }: TranslateActionProps): DocumentActionDescription | null => {\n const document = draft ?? published\n const [isDialogOpen, setIsDialogOpen] = useState(false)\n\n devLog.debug('TranslateAction initialized', {\n documentId: document?._id,\n documentType: document?._type,\n })\n\n if (!document || !config.translatableSchemaTypes?.includes(document._type)) {\n devLog.warn('Document not in translatable schema types', {\n documentType: document?._type,\n translatableTypes: config.translatableSchemaTypes,\n })\n return null\n }\n\n if (!config) {\n devLog.error('Missing config in TranslateAction')\n return null\n }\n\n return {\n label: 'Translate',\n icon: TranslateIcon,\n onHandle: () => {\n devLog.info('Translation dialog opened', {\n documentId: document._id,\n documentType: document._type,\n component: 'TranslateAction',\n })\n setIsDialogOpen(true)\n },\n dialog: isDialogOpen && {\n type: 'dialog',\n onClose: () => setIsDialogOpen(false),\n header: 'Translate Document',\n content: (\n <TranslationContextProvider document={document as TranslatableDocument} config={config}>\n <TranslationDialog setIsDialogOpen={setIsDialogOpen} />\n </TranslationContextProvider>\n ),\n },\n }\n }\n}\n","import { definePlugin } from 'sanity'\nimport { getGiveTranslationFeedbackAction } from './GiveTranslationFeedbackAction'\nimport { translationGlossaryTerm } from './schemas/translationGlossaryTerm.schema'\nimport { translationHistory } from './schemas/translationHistory.schema'\nimport { translationSettings } from './schemas/translationSettings.schema'\nimport { getTranslateAction } from './TranslateAction'\nimport type { PluginConfig } from './types'\n\n/**\n * AI translation plugin for Sanity Studio\n * See the PluginConfig export for configuration options\n *\n * @public\n */\nexport const aiTranslationPlugin = definePlugin<PluginConfig>((config) => {\n return {\n name: 'sanity-plugin-ai-translation',\n document: {\n actions: [getTranslateAction(config), getGiveTranslationFeedbackAction(config)],\n },\n schema: {\n types: [translationSettings, translationGlossaryTerm],\n },\n }\n})\n\n/**\n * Schema for translation history\n *\n * @public\n */\nexport const translationHistorySchema = translationHistory\n"],"names":["translationHistory","translationSettings","result"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/hooks/useTranslationContext/TranslationContext.ts","../src/hooks/useTranslationContext/useTranslationContext.ts","../src/consts.ts","../src/utils/undraftId.ts","../src/hooks/useTranslationMetadata/useTranslationMetadata.ts","../src/utils/devLog.ts","../src/utils/processFeedback.ts","../src/components/ProgressPanel.tsx","../src/components/SuggestionReviewList.tsx","../src/components/GiveFeedbackDialog.tsx","../src/hooks/useTranslationContext/translationReducer.ts","../src/hooks/useTranslationContext/TranslationContextProvider.tsx","../src/GiveTranslationFeedbackAction.tsx","../src/schemas/translationGlossaryTerm.schema.ts","../src/schemas/translationHistory.schema.ts","../src/schemas/translationSettings.schema.ts","../src/utils/fetchTranslationPrompts.ts","../src/utils/findKeyValues/findKeyValues.ts","../src/utils/localizeReferences.ts","../src/utils/Semaphore.ts","../src/utils/setupTranslationJobStatuses.ts","../src/utils/getExistingTranslationId.ts","../src/utils/determineTranslationTarget.ts","../src/utils/getTranslationMetadata.ts","../src/utils/setJobStatus.ts","../src/utils/translateDocumentInPlace.ts","../src/utils/assembleLanguageSpecs.ts","../src/utils/translateEntireDocument.ts","../src/utils/updateTranslationMetadata.ts","../src/utils/translateDocument.ts","../src/utils/translateDocumentSet.ts","../src/components/ActionButtonBar.tsx","../src/components/LanguageCheckbox.tsx","../src/components/LanguageSelectionPanel.tsx","../src/utils/assembleReferences.ts","../src/components/ReferenceConfigPanel.tsx","../src/components/WriteSettingsPanel.tsx","../src/components/TranslationConfigPanel.tsx","../src/components/TranslationStatusPanel.tsx","../src/components/TranslationDialog.tsx","../src/TranslateAction.tsx","../src/index.ts"],"sourcesContent":["import { createContext } from 'react'\nimport type { TranslationJob, TranslationContext as TTranslationContext } from '../../types'\n\nexport const TranslationContext = createContext<TTranslationContext>({\n document: null,\n config: null,\n overallStatus: 'idle',\n selectedTargetLanguages: [],\n translationJobs: new Map<string, TranslationJob>(),\n shouldTranslateDiffs: false,\n shouldOverwriteFreshTranslations: false,\n shouldTranslateReferences: false,\n maxReferenceDepth: 1,\n references: [],\n translationMetadata: null,\n dispatch: () => {},\n})\n","import { useContext } from 'react'\nimport type { TranslationContext as TTranslationContext } from '../../types'\nimport { TranslationContext } from './TranslationContext'\n\ninterface ValidatedTranslationContext extends TTranslationContext {\n document: NonNullable<TTranslationContext['document']>\n config: NonNullable<TTranslationContext['config']>\n}\n\nexport const useTranslationContext = (): ValidatedTranslationContext => {\n const context = useContext(TranslationContext)\n\n if (!context.document || !context.config) {\n throw new Error(\n 'useTranslationContext must be used within a TranslationContextProvider with document and config props',\n )\n }\n\n return context as ValidatedTranslationContext\n}\n","export const TRANSLATION_METADATA_TYPE = 'translation.metadata'\nexport const UPDATE_EXISTING_TRANSLATION_PROMPT =\n '***IMPORTANT:** This document has an existing, but out-of-date translation. Please review the existing translation before processing and change as little as possible. Existing translation: $extantTranslation'\n","// Remove `drafts.` from a string\nexport const undraftId = (id: string) => id.replace(/^drafts\\./, '')\n\nexport const draftId = (id: string) => `drafts.${undraftId(id)}`\n","import { useEffect } from 'react'\nimport { useListeningQuery } from 'sanity-plugin-utils'\nimport { TRANSLATION_METADATA_TYPE } from '../../consts'\nimport type { TranslationMetadataDocument } from '../../types'\nimport { undraftId } from '../../utils/undraftId'\nimport { useTranslationContext } from '../useTranslationContext'\n\nconst TRANSLATION_METADATA_QUERY = '*[_type == $translationMetadataType && references($documentId)][0]'\n\ninterface UseTranslationMetadataProps {\n documentId: string\n}\n\nexport const useTranslationMetadata = ({ documentId }: UseTranslationMetadataProps) => {\n const { dispatch } = useTranslationContext()\n\n const { data, loading, error } = useListeningQuery<TranslationMetadataDocument | null>(TRANSLATION_METADATA_QUERY, {\n params: {\n documentId: undraftId(documentId),\n translationMetadataType: TRANSLATION_METADATA_TYPE,\n },\n initialValue: null,\n })\n\n useEffect(() => {\n if (loading) {\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'fetching_metadata' })\n return\n }\n\n if (error) {\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'error' })\n return\n }\n\n if (data) {\n dispatch({ type: 'SET_TRANSLATION_METADATA', payload: data as TranslationMetadataDocument })\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'idle' })\n return\n }\n\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'idle' })\n }, [data, loading, error, dispatch])\n\n return {\n data,\n loading,\n error,\n }\n}\n","/**\n * Development logging utility for AI Translation plugin troubleshooting\n * Only logs when SANITY_STUDIO_AI_TRANSLATION_PLUGIN_LOGGING environment variable is \"true\"\n */\n\nconst isLoggingEnabled = (): boolean => {\n return process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLATION_PLUGIN_LOGGING === 'true'\n}\n\nexport interface DevLogContext {\n component?: string\n action?: string\n documentId?: string\n language?: string\n jobId?: string\n // biome-ignore lint/suspicious/noExplicitAny: not worth the effort\n [key: string]: any\n}\n\nexport const devLog = {\n info: (message: string, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.info('[AI Translation]', message, context ? JSON.stringify(context, null, 2) : '')\n },\n\n warn: (message: string, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.warn('[AI Translation]', message, context ? JSON.stringify(context, null, 2) : '')\n },\n\n error: (message: string, error?: Error | unknown, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.error('[AI Translation]', message, error, context ? JSON.stringify(context, null, 2) : '')\n },\n\n debug: (message: string, data?: unknown, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.debug('[AI Translation]', message, data, context ? JSON.stringify(context, null, 2) : '')\n },\n\n group: (label: string, context?: DevLogContext) => {\n if (!isLoggingEnabled()) return\n console.group(`[AI Translation] ${label}`, context ? JSON.stringify(context, null, 2) : '')\n },\n\n groupEnd: () => {\n if (!isLoggingEnabled()) return\n console.groupEnd()\n },\n\n time: (label: string) => {\n if (!isLoggingEnabled()) return\n console.time(`[AI Translation] ${label}`)\n },\n\n timeEnd: (label: string) => {\n if (!isLoggingEnabled()) return\n console.timeEnd(`[AI Translation] ${label}`)\n },\n}\n","import type { SanityClient } from 'sanity'\nimport type { FeedbackSuggestion } from '../types'\nimport { devLog } from './devLog'\n\ninterface ProcessFeedbackOptions {\n client: SanityClient\n schemaId: string\n sourceLanguage: string\n targetLanguage: string\n userFeedback?: string\n shouldIncludeEdits: boolean\n sourceSnapshot?: string\n targetSnapshot?: string\n currentDocument?: Record<string, unknown>\n onProgress?: (state: { stage: 'analyzing' | 'applying'; message: string }) => void\n}\n\ninterface AnalyzeFeedbackOptions {\n client: SanityClient\n schemaId: string\n sourceLanguage: string\n targetLanguage: string\n userFeedback?: string\n shouldIncludeEdits: boolean\n sourceSnapshot?: string\n targetSnapshot?: string\n currentDocument?: Record<string, unknown>\n onProgress?: (state: { stage: 'analyzing'; message: string }) => void\n}\n\ninterface ApplySuggestionsOptions {\n client: SanityClient\n schemaId: string\n sourceLanguage: string\n targetLanguage: string\n suggestions: FeedbackSuggestion[]\n onProgress?: (state: { stage: 'applying'; message: string }) => void\n}\n\ninterface FeedbackAnalysis {\n globalPromptUpdates?: string\n localePromptUpdates?: string\n protectedPhrasesToAdd?: string[]\n glossaryTermsToAdd?: Array<{\n sourceLocale: string\n targetLocale: string\n sourceValue: string\n targetValue: string\n }>\n reasoning: string\n}\n\n/**\n * Analyzes user feedback and inferred edits to generate improvement suggestions.\n *\n * This function:\n * 1. Analyzes explicit user feedback and/or edits made to translated content\n * 2. Uses AI to infer improvements to translation settings\n * 3. Returns a list of suggestions for the user to review\n *\n * @param options - Configuration for feedback analysis\n * @returns Promise that resolves with array of feedback suggestions\n */\nexport async function analyzeFeedback({\n client,\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n onProgress,\n}: AnalyzeFeedbackOptions): Promise<FeedbackSuggestion[]> {\n devLog.info('Starting feedback analysis', {\n sourceLanguage,\n targetLanguage,\n hasUserFeedback: !!userFeedback,\n shouldIncludeEdits,\n })\n\n onProgress?.({ stage: 'analyzing', message: 'Analyzing feedback and edits...' })\n\n const analysisPrompt = buildAnalysisPrompt({\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n })\n\n const analysis = await analyzeWithAI(client, analysisPrompt)\n devLog.info('AI analysis complete', { analysis })\n\n const suggestions = convertAnalysisToSuggestions(analysis)\n devLog.info('Generated suggestions', { count: suggestions.length })\n\n return suggestions\n}\n\n/**\n * Applies approved feedback suggestions to translation settings and glossary.\n *\n * @param options - Configuration for applying suggestions\n * @returns Promise that resolves when suggestions have been applied\n */\nexport async function applySuggestions({\n client,\n schemaId,\n sourceLanguage,\n targetLanguage,\n suggestions,\n onProgress,\n}: ApplySuggestionsOptions): Promise<void> {\n devLog.info('Applying suggestions', {\n sourceLanguage,\n targetLanguage,\n targetLanguageType: typeof targetLanguage,\n targetLanguageValue: targetLanguage,\n count: suggestions.filter((s) => s.approved).length,\n })\n\n if (!targetLanguage) {\n devLog.error('targetLanguage is undefined in applySuggestions!', {\n sourceLanguage,\n targetLanguage,\n suggestionsCount: suggestions.length,\n })\n throw new Error('targetLanguage is required but was undefined')\n }\n\n const approvedSuggestions = suggestions.filter((s) => s.approved)\n\n if (approvedSuggestions.length === 0) {\n devLog.info('No approved suggestions to apply')\n return\n }\n\n onProgress?.({ stage: 'applying', message: 'Applying updates to translation settings...' })\n\n await applyImprovementsFromSuggestions(client, schemaId, targetLanguage, approvedSuggestions, onProgress)\n\n devLog.info('Suggestions applied successfully')\n}\n\n/**\n * Processes user feedback and inferred edits to improve translation prompts and glossary.\n * This is a convenience function that combines analysis and application in one step.\n *\n * @deprecated Use analyzeFeedback and applySuggestions separately for better UX\n * @param options - Configuration for feedback processing\n * @returns Promise that resolves when feedback has been processed\n */\nexport async function processFeedback({\n client,\n schemaId,\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n onProgress,\n}: ProcessFeedbackOptions): Promise<void> {\n const suggestions = await analyzeFeedback({\n client,\n schemaId,\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n onProgress: onProgress ? (state) => onProgress({ ...state, stage: 'analyzing' }) : undefined,\n })\n\n await applySuggestions({\n client,\n schemaId,\n sourceLanguage,\n targetLanguage,\n suggestions,\n onProgress: onProgress ? (state) => onProgress({ ...state, stage: 'applying' }) : undefined,\n })\n}\n\n/**\n * Builds the prompt for AI analysis of user feedback and edits.\n */\nfunction buildAnalysisPrompt({\n sourceLanguage,\n targetLanguage,\n userFeedback,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument,\n}: {\n sourceLanguage: string\n targetLanguage: string\n userFeedback?: string\n shouldIncludeEdits: boolean\n sourceSnapshot?: string\n targetSnapshot?: string\n currentDocument?: Record<string, unknown>\n}): string {\n const parts: string[] = [\n 'You are analyzing feedback about AI translation quality to improve future translations.',\n `Source language: ${sourceLanguage}`,\n `Target language: ${targetLanguage}`,\n '',\n 'Your task is to analyze the feedback and infer specific improvements to:',\n '1. Global translation prompt (general guidance for all translations)',\n '2. Locale-specific prompt (guidance specific to this target language)',\n '3. Protected phrases (terms that should never be translated)',\n '4. Glossary terms (specific term-to-term translation mappings)',\n '',\n ]\n\n if (userFeedback) {\n parts.push('USER FEEDBACK:', userFeedback, '')\n }\n\n if (shouldIncludeEdits && sourceSnapshot && targetSnapshot && currentDocument) {\n parts.push(\n 'EDIT ANALYSIS:',\n 'Compare the original translation with the edited version to understand what the user changed.',\n '',\n 'Original source document:',\n sourceSnapshot,\n '',\n 'Original AI translation:',\n targetSnapshot,\n '',\n 'Current edited document:',\n JSON.stringify(currentDocument, null, 2),\n '',\n )\n }\n\n parts.push(\n 'INSTRUCTIONS:',\n 'Analyze the feedback and/or edits to identify patterns and improvements.',\n '',\n 'For edits, look for:',\n '- Terminology changes that suggest glossary additions',\n '- Phrases that were protected/unprotected incorrectly',\n '- Style, tone, or formatting issues that suggest prompt improvements',\n '- Consistent patterns across multiple changes',\n '',\n 'IMPORTANT RULES:',\n '1. DO NOT create redundant updates. Choose ONE mechanism for each issue:',\n ' - Protected phrases = terms that should NEVER be translated (language-agnostic)',\n ' - Glossary terms = specific translation mappings (e.g., \"chat\" → \"cat\" in French)',\n ' - Locale prompts = guidance specific to this source→target language pair',\n ' - Global prompts = guidance that applies to ALL translations',\n '',\n '2. Be locale-specific:',\n ` - This feedback is specifically about ${sourceLanguage} → ${targetLanguage} translation`,\n ' - DO NOT assume rules apply to other language pairs unless explicitly stated',\n ' - Prefer locale-specific prompts over global prompts unless universally applicable',\n '',\n '3. Protected phrases vs. Locale prompts:',\n ' - Use protected phrases ONLY for brand names, product names, proper nouns, technical terms that should NEVER be translated in ANY language',\n ' - Use locale prompts for language-pair-specific guidance (e.g., \"Keep technical terms in English when translating to German\")',\n ' - NEVER mention specific terms in both protected phrases AND prompts',\n '',\n '4. Glossary vs. Protected phrases:',\n ' - Glossary = \"Always translate X as Y\" (provides the correct translation)',\n ' - Protected = \"Never translate X\" (keeps it as-is)',\n ' - CRITICAL: If sourceValue === targetValue, use PROTECTED PHRASES, NOT glossary',\n ' - Only use glossary when the term actually changes between languages',\n ' - Use protected when the term should remain unchanged across all languages',\n '',\n 'Output a JSON object with this structure:',\n '{',\n ' \"globalPromptUpdates\": \"string | null - ONLY if this applies to ALL language pairs\",',\n ` \"localePromptUpdates\": \"string | null - ONLY if this is specific to ${sourceLanguage}→${targetLanguage}\",`,\n ' \"protectedPhrasesToAdd\": [\"ONLY brand names, products, proper nouns that should NEVER translate\"],',\n ' \"glossaryTermsToAdd\": [{\"sourceLocale\": \"sourceLocale\",\"sourceValue\": \"term\", \"targetLocale\": \"targetLocale\", \"targetValue\": \"translation\"} - ONLY specific term mappings],',\n ' \"reasoning\": \"string - Explain your analysis and which mechanism you chose for each issue\"',\n '}',\n '',\n 'Be conservative: only suggest changes when there is clear evidence.',\n 'If in doubt, prefer locale-specific updates over global updates.',\n 'Avoid redundancy - if you add a protected phrase, do NOT mention it in prompts.',\n )\n\n return parts.join('\\n')\n}\n\n/**\n * Converts AI analysis results into user-reviewable suggestions.\n */\nfunction convertAnalysisToSuggestions(analysis: FeedbackAnalysis): FeedbackSuggestion[] {\n const suggestions: FeedbackSuggestion[] = []\n\n if (analysis.globalPromptUpdates) {\n suggestions.push({\n id: crypto.randomUUID(),\n type: 'globalPrompt',\n description: analysis.globalPromptUpdates,\n approved: true,\n })\n }\n\n if (analysis.localePromptUpdates) {\n suggestions.push({\n id: crypto.randomUUID(),\n type: 'localePrompt',\n description: analysis.localePromptUpdates,\n approved: true,\n })\n }\n\n if (analysis.protectedPhrasesToAdd) {\n for (const phrase of analysis.protectedPhrasesToAdd) {\n suggestions.push({\n id: crypto.randomUUID(),\n type: 'protectedPhrase',\n description: phrase,\n approved: true,\n })\n }\n }\n\n if (analysis.glossaryTermsToAdd) {\n for (const term of analysis.glossaryTermsToAdd) {\n suggestions.push({\n id: crypto.randomUUID(),\n type: 'glossaryTerm',\n description: `${term.sourceValue} → ${term.targetValue}`,\n approved: true,\n sourceLocale: term.sourceLocale,\n sourceValue: term.sourceValue,\n targetLocale: term.targetLocale,\n targetValue: term.targetValue,\n })\n }\n }\n\n return suggestions\n}\n\n/**\n * Uses Sanity AI Agent to analyze feedback and infer improvements.\n */\nasync function analyzeWithAI(client: SanityClient, prompt: string): Promise<FeedbackAnalysis> {\n try {\n const response = await client.agent.action.prompt({\n instruction: prompt,\n format: 'json',\n })\n\n devLog.debug('AI response received', { responseType: typeof response })\n\n const responseText =\n typeof response === 'string'\n ? response\n : response && typeof response === 'object'\n ? JSON.stringify(response)\n : (() => {\n throw new Error(`Unexpected response type: ${typeof response}`)\n })()\n\n return parseAIResponse(responseText)\n } catch (error) {\n devLog.error('Error during AI analysis', { error })\n throw new Error(`Failed to analyze feedback: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n}\n\n/**\n * Parses the AI response text to extract the feedback analysis.\n */\nfunction parseAIResponse(responseText: string): FeedbackAnalysis {\n try {\n let parsed: unknown\n try {\n parsed = JSON.parse(responseText)\n } catch {\n const jsonMatch = responseText.match(/\\{[\\s\\S]*\\}/)\n if (!jsonMatch) throw new Error('No JSON found in AI response')\n parsed = JSON.parse(jsonMatch[0])\n }\n\n if (!parsed || typeof parsed !== 'object') {\n throw new Error('Response is not a valid object')\n }\n\n const analysis = parsed as FeedbackAnalysis\n if (typeof analysis.reasoning !== 'string') {\n throw new Error('Invalid response structure: missing reasoning')\n }\n\n return {\n globalPromptUpdates: analysis.globalPromptUpdates || undefined,\n localePromptUpdates: analysis.localePromptUpdates || undefined,\n protectedPhrasesToAdd: Array.isArray(analysis.protectedPhrasesToAdd) ? analysis.protectedPhrasesToAdd : [],\n glossaryTermsToAdd: Array.isArray(analysis.glossaryTermsToAdd) ? analysis.glossaryTermsToAdd : [],\n reasoning: analysis.reasoning,\n }\n } catch (error) {\n devLog.error('Error parsing AI response', { error, responseText })\n throw new Error('Failed to parse AI response as JSON')\n }\n}\n\n/**\n * Applies the inferred improvements from suggestions to translation settings and glossary.\n */\nasync function applyImprovementsFromSuggestions(\n client: SanityClient,\n schemaId: string,\n targetLanguage: string,\n suggestions: FeedbackSuggestion[],\n onProgress?: (state: { stage: 'applying'; message: string }) => void,\n): Promise<void> {\n devLog.info('Applying improvements from suggestions', { count: suggestions.length })\n\n const settingsId = 'translation-settings'\n\n // Create the document if it doesn't exist\n const settings = await client.fetch('*[_id == $id][0]', { id: settingsId })\n if (!settings) {\n await client.createIfNotExists({\n _id: settingsId,\n _type: 'translationSettings',\n })\n }\n\n const updates: Array<Promise<unknown>> = []\n\n // Group suggestions by type and filter out empty values\n const globalPrompts = suggestions.filter((s) => s.type === 'globalPrompt' && s.description.trim())\n const localePrompts = suggestions.filter((s) => s.type === 'localePrompt' && s.description.trim())\n const protectedPhrases = suggestions.filter((s) => s.type === 'protectedPhrase' && s.description.trim())\n const glossaryTerms = suggestions.filter(\n (s) =>\n s.type === 'glossaryTerm' &&\n s.sourceLocale?.trim() &&\n s.sourceValue?.trim() &&\n s.targetLocale?.trim() &&\n s.targetValue?.trim(),\n )\n\n devLog.info('Filtered suggestions by type', {\n globalPrompts: globalPrompts.length,\n localePrompts: localePrompts.length,\n protectedPhrases: protectedPhrases.length,\n glossaryTerms: glossaryTerms.length,\n })\n\n // Apply both global and locale prompts in a single transform call\n if (globalPrompts.length > 0 || localePrompts.length > 0) {\n onProgress?.({\n stage: 'applying',\n message:\n globalPrompts.length > 0 && localePrompts.length > 0\n ? 'Updating global and locale translation prompts...'\n : globalPrompts.length > 0\n ? 'Updating global translation prompt...'\n : `Updating ${targetLanguage} translation prompt...`,\n })\n\n updates.push(updatePromptsWithTransform(client, schemaId, settingsId, targetLanguage, globalPrompts, localePrompts))\n }\n\n // Apply protected phrases\n if (protectedPhrases.length > 0) {\n onProgress?.({ stage: 'applying', message: 'Adding protected phrases...' })\n const phrases = protectedPhrases.map((s) => s.description)\n devLog.debug('Applying protected phrases', { phrases })\n updates.push(addProtectedPhrases(client, settingsId, phrases))\n }\n\n // Apply glossary terms\n if (glossaryTerms.length > 0) {\n onProgress?.({ stage: 'applying', message: 'Adding glossary terms...' })\n const terms = glossaryTerms.map((s) => ({\n // biome-ignore-start lint/style/noNonNullAssertion: safely handled\n sourceLocale: s.sourceLocale!,\n sourceValue: s.sourceValue!,\n targetLocale: s.targetLocale!,\n targetValue: s.targetValue!,\n // biome-ignore-end lint/style/noNonNullAssertion: safely handled\n }))\n devLog.debug('Applying glossary terms', { terms })\n updates.push(addGlossaryTerms(client, terms))\n }\n\n if (updates.length === 0) {\n devLog.warn('No valid updates to apply - all suggestions may have been empty')\n }\n\n await Promise.all(updates)\n devLog.info('All improvements applied successfully')\n}\n\n/**\n * Updates both global and locale prompts using a single transform action.\n * This uses Sanity Agent transform with multiple targets for efficient updates.\n */\nasync function updatePromptsWithTransform(\n client: SanityClient,\n schemaId: string,\n settingsId: string,\n targetLanguage: string,\n globalPrompts: FeedbackSuggestion[],\n localePrompts: FeedbackSuggestion[],\n): Promise<void> {\n devLog.info('Updating prompts with transform action', {\n settingsId,\n targetLanguage,\n targetLanguageType: typeof targetLanguage,\n targetLanguageValue: targetLanguage,\n hasGlobalUpdates: globalPrompts.length > 0,\n hasLocaleUpdates: localePrompts.length > 0,\n })\n\n if (!targetLanguage) {\n devLog.error('targetLanguage is undefined or empty!', {\n targetLanguage,\n globalPrompts: globalPrompts.length,\n localePrompts: localePrompts.length,\n })\n throw new Error('targetLanguage is required but was undefined')\n }\n\n // Build targets array for transform action\n const targets: Array<{\n path: string | string[]\n instruction: string\n }> = []\n\n // Add global prompt target if we have updates\n if (globalPrompts.length > 0) {\n const combinedGlobalUpdate = globalPrompts.map((s) => s.description).join('\\n\\n')\n targets.push({\n path: 'globalPrompt',\n instruction: `You are updating a translation prompt document that contains rules and guidance for future AI translations.\n\nIMPORTANT: The text below is NEW GUIDANCE that should be INCORPORATED INTO the existing prompt as additional rules/instructions for future translations. DO NOT apply or execute these rules on the prompt text itself.\n\nYour task: Merge the new guidance below into the existing prompt text. Treat the new guidance as rules that will guide future translations, not as transformations to apply to the current text.\n\nIntegration guidelines:\n- Add the new guidance as additional instructions/rules in the prompt\n- If it conflicts with existing guidance, update or replace the conflicting parts\n- If it's already covered, don't add redundant text\n- Maintain clear structure and consistent tone\n- Preserve all existing guidance that is still relevant\n- Keep the prompt written as instructions for a translator (e.g., \"When translating, you should...\" not \"The translation has been...\")\n\nNew guidance to incorporate:\n\n\\`\\`\\`\n${combinedGlobalUpdate}\n\\`\\`\\``,\n })\n devLog.debug('Added global prompt target', { combinedUpdate: combinedGlobalUpdate })\n }\n\n // Add locale prompt target if we have updates\n if (localePrompts.length > 0) {\n const combinedLocaleUpdate = localePrompts.map((s) => s.description).join('\\n\\n')\n\n // Check if locale prompt exists, if not create it first\n const existingLocalePrompts = await client.fetch<Array<{ _key: string; value: string }>>(\n '*[_id == $settingsId][0].localePrompts',\n { settingsId },\n )\n\n const hasExistingLocalePrompt = existingLocalePrompts?.some((lp) => lp._key === targetLanguage)\n devLog.debug('Checking existing locale prompt', {\n targetLanguage,\n hasExistingLocalePrompt,\n existingCount: existingLocalePrompts?.length || 0,\n })\n\n if (!hasExistingLocalePrompt) {\n // Create the locale prompt entry first\n devLog.info('Creating new locale prompt entry', { targetLanguage })\n await client\n .patch(settingsId)\n .setIfMissing({ localePrompts: [] })\n .append('localePrompts', [\n {\n _type: 'internationalizedArrayTextValue',\n _key: targetLanguage,\n value: '', // Start with empty value, transform will fill it\n },\n ])\n .commit()\n }\n\n // Use dot notation path for the locale prompt value\n const localePromptPath = ['localePrompts', { _key: targetLanguage }, 'value']\n\n targets.push({\n // @ts-expect-error\n path: localePromptPath,\n instruction: `You are updating a translation prompt document that contains rules and guidance for future AI translations.\n\nIMPORTANT: The text below is NEW GUIDANCE that should be INCORPORATED INTO the existing prompt as additional rules/instructions for future translations. DO NOT apply or execute these rules on the prompt text itself.\n\nYour task: Merge the new guidance below into the existing prompt text. Treat the new guidance as rules that will guide future translations, not as transformations to apply to the current text.\n\nIntegration guidelines:\n- Add the new guidance as additional instructions/rules in the prompt\n- If it conflicts with existing guidance, update or replace the conflicting parts\n- If it's already covered, don't add redundant text\n- Maintain clear structure and consistent tone\n- Preserve all existing guidance that is still relevant\n- Keep the prompt written as instructions for a translator (e.g., \"When translating, you should...\" not \"The translation has been...\")\n\nNew guidance to incorporate:\n\n\\`\\`\\`\n${combinedLocaleUpdate}\n\\`\\`\\``,\n })\n devLog.debug('Added locale prompt target', {\n targetLanguage,\n localePromptPath,\n combinedUpdate: combinedLocaleUpdate,\n })\n }\n\n // Use transform action with multiple targets\n const result = await client.agent.action.transform({\n schemaId,\n documentId: settingsId,\n instruction: 'Update translation prompts based on user feedback to improve future translations.',\n target: targets,\n forcePublishedWrite: true,\n })\n\n devLog.info('Prompts updated via transform action', {\n resultId: result._id,\n globalUpdated: globalPrompts.length > 0,\n localeUpdated: localePrompts.length > 0,\n })\n}\n\n/**\n * Adds new protected phrases to the translation settings.\n */\nasync function addProtectedPhrases(client: SanityClient, settingsId: string, phrases: string[]): Promise<void> {\n devLog.info('Adding protected phrases', { settingsId, phrasesCount: phrases.length, phrases })\n\n const currentPhrases = await client.fetch<string[]>('*[_id == $settingsId][0].protectedPhrases', { settingsId })\n devLog.debug('Fetched current protected phrases', { currentCount: currentPhrases?.length })\n\n const newPhrases = phrases.filter((phrase) => !currentPhrases?.includes(phrase))\n\n if (newPhrases.length === 0) {\n devLog.info('No new protected phrases to add (all already exist)')\n return\n }\n\n const result = await client\n .patch(settingsId)\n .setIfMissing({ protectedPhrases: [] })\n .append('protectedPhrases', newPhrases)\n .commit()\n\n devLog.info('Protected phrases added', { count: newPhrases.length, phrases: newPhrases, resultId: result._id })\n}\n\n/**\n * Adds new glossary terms or updates existing ones.\n * Creates glossary terms with translations in both source and target languages.\n */\nasync function addGlossaryTerms(\n client: SanityClient,\n terms: Array<{ sourceLocale: string; sourceValue: string; targetLocale: string; targetValue: string }>,\n): Promise<void> {\n // Filter out terms where source === target (these should be protected phrases instead)\n const validTerms = terms.filter(({ sourceValue, targetValue }) => {\n if (sourceValue === targetValue) {\n devLog.warn('Skipping glossary term where source === target (should be a protected phrase)', {\n sourceValue,\n targetValue,\n })\n return false\n }\n return true\n })\n\n if (validTerms.length === 0) {\n devLog.info('No valid glossary terms to add')\n return\n }\n\n for (const { sourceLocale, sourceValue, targetLocale, targetValue } of validTerms) {\n const existingTerm = await client.fetch<{\n _id: string\n translations: Array<{ _key: string; value: string }>\n } | null>(\n `*[_type == \"translationGlossaryTerm\" && count(translations[_key == $sourceLocale && value == $sourceValue]) > 0\n ][0] {\n _id,\n translations\n }`,\n { sourceLocale, sourceValue },\n )\n\n if (existingTerm) {\n const hasTargetTranslation = existingTerm.translations.some((t) => t._key === targetLocale)\n\n if (!hasTargetTranslation) {\n await client\n .patch(existingTerm._id)\n .append('translations', [\n {\n _type: 'internationalizedArrayStringValue',\n _key: targetLocale,\n value: targetValue,\n },\n ])\n .commit()\n\n devLog.info('Updated existing glossary term', { sourceLocale, sourceValue, targetLocale, targetValue })\n } else {\n devLog.info('Glossary term already has this translation', {\n sourceLocale,\n sourceValue,\n targetLocale,\n targetValue,\n })\n }\n } else {\n await client.create({\n _type: 'translationGlossaryTerm',\n translations: [\n {\n _type: 'internationalizedArrayStringValue',\n _key: sourceLocale,\n value: sourceValue,\n },\n {\n _type: 'internationalizedArrayStringValue',\n _key: targetLocale,\n value: targetValue,\n },\n ],\n })\n\n devLog.info('Created new glossary term', { sourceLocale, sourceValue, targetLocale, targetValue })\n }\n }\n\n devLog.info('Glossary terms processed', {\n totalRequested: terms.length,\n validAdded: validTerms.length,\n skipped: terms.length - validTerms.length,\n })\n}\n","import { CheckmarkCircleIcon, ErrorOutlineIcon } from '@sanity/icons'\nimport { Card, type CardTone, Flex, Spinner, Stack, Text } from '@sanity/ui'\nimport type { FC } from 'react'\n\ntype ProgressPanelStatus = 'in_progress' | 'completed' | 'error'\n\ninterface ProgressPanelProps {\n title?: string\n description?: string\n tone?: CardTone\n status?: ProgressPanelStatus\n icon?: React.ReactNode\n}\n\nconst ICON_SIZE = 64\n\nconst progressIconMap: Record<ProgressPanelStatus, React.ReactNode> = {\n in_progress: <Spinner />,\n completed: <CheckmarkCircleIcon fontSize={ICON_SIZE} />,\n error: <ErrorOutlineIcon fontSize={ICON_SIZE} />,\n}\n\nexport const ProgressPanel: FC<ProgressPanelProps> = ({\n title,\n description,\n tone,\n status = 'in_progress',\n icon,\n ...props\n}) => {\n return (\n <Card tone={tone} padding={4} {...props}>\n <Flex gap={4} align=\"center\" justify=\"center\">\n {icon || progressIconMap[status]}\n <Stack space={3}>\n {title && (\n <Text size={2} weight=\"bold\">\n {title}\n </Text>\n )}\n {description && (\n <Text size={1} muted>\n {description}\n </Text>\n )}\n </Stack>\n </Flex>\n </Card>\n )\n}\n","import { AddIcon, EmptyIcon, TrashIcon } from '@sanity/icons'\nimport { Box, Button, Card, Checkbox, Flex, Select, Stack, Text, TextArea, TextInput } from '@sanity/ui'\nimport { type FC, useState } from 'react'\nimport type { FeedbackSuggestion, ImprovementType } from '../types'\nimport { ProgressPanel } from './ProgressPanel'\n\ninterface SuggestionReviewListProps {\n suggestions: FeedbackSuggestion[]\n onSuggestionsChange: (suggestions: FeedbackSuggestion[]) => void\n}\n\nconst IMPROVEMENT_TYPE_LABELS: Record<ImprovementType, string> = {\n globalPrompt: 'Global Prompt',\n localePrompt: 'Locale Prompt',\n protectedPhrase: 'Protected Phrase',\n glossaryTerm: 'Glossary Term',\n}\n\n/**\n * Creates a new empty suggestion with default values\n */\nconst createNewSuggestion = (type: ImprovementType = 'protectedPhrase'): FeedbackSuggestion => {\n const baseSuggestion: FeedbackSuggestion = {\n id: crypto.randomUUID(),\n type,\n description: '',\n approved: true,\n }\n\n if (type === 'glossaryTerm') {\n return {\n ...baseSuggestion,\n sourceValue: '',\n targetValue: '',\n }\n }\n\n return baseSuggestion\n}\n\nexport const SuggestionReviewList: FC<SuggestionReviewListProps> = ({ suggestions, onSuggestionsChange }) => {\n const [editingId, setEditingId] = useState<string | null>(null)\n\n const handleToggleApproval = (id: string) => {\n const updated = suggestions.map((s) => (s.id === id ? { ...s, approved: !s.approved } : s))\n onSuggestionsChange(updated)\n }\n\n const handleTypeChange = (id: string, newType: ImprovementType) => {\n const updated = suggestions.map((s) => {\n if (s.id !== id) {\n return s\n }\n\n // If changing to/from glossaryTerm, we need to handle sourceValue/targetValue\n if (newType === 'glossaryTerm' && s.type !== 'glossaryTerm') {\n // Parse description if it looks like \"source → target\"\n const match = s.description.match(/^(.+?)\\s*→\\s*(.+)$/)\n return {\n ...s,\n type: newType,\n sourceValue: match ? match[1].trim() : '',\n targetValue: match ? match[2].trim() : '',\n }\n }\n if (newType !== 'glossaryTerm' && s.type === 'glossaryTerm') {\n // Convert back to simple description\n return {\n ...s,\n type: newType,\n description: s.sourceValue && s.targetValue ? `${s.sourceValue} → ${s.targetValue}` : s.description,\n sourceValue: undefined,\n targetValue: undefined,\n }\n }\n return { ...s, type: newType }\n })\n onSuggestionsChange(updated)\n }\n\n const handleDescriptionChange = (id: string, newDescription: string) => {\n const updated = suggestions.map((s) => (s.id === id ? { ...s, description: newDescription } : s))\n onSuggestionsChange(updated)\n }\n\n const handleGlossarySourceChange = (id: string, newSource: string) => {\n const updated = suggestions.map((s) =>\n s.id === id\n ? {\n ...s,\n sourceValue: newSource,\n description: `${newSource} → ${s.targetValue || ''}`,\n }\n : s,\n )\n onSuggestionsChange(updated)\n }\n\n const handleGlossaryTargetChange = (id: string, newTarget: string) => {\n const updated = suggestions.map((s) =>\n s.id === id\n ? {\n ...s,\n targetValue: newTarget,\n description: `${s.sourceValue || ''} → ${newTarget}`,\n }\n : s,\n )\n onSuggestionsChange(updated)\n }\n\n const handleRemove = (id: string) => {\n const updated = suggestions.filter((s) => s.id !== id)\n onSuggestionsChange(updated)\n }\n\n const handleAddSuggestion = (type: ImprovementType) => {\n const newSuggestion = createNewSuggestion(type)\n onSuggestionsChange([...suggestions, newSuggestion])\n // Auto-focus on the new suggestion by setting it as editing\n setEditingId(newSuggestion.id)\n }\n\n if (suggestions.length === 0) {\n return (\n <Stack space={3}>\n <ProgressPanel\n status=\"error\"\n tone=\"transparent\"\n title=\"No suggestions generated\"\n description='Try providing more specific feedback or enabling \"Include Edits\".'\n icon={<EmptyIcon fontSize={24} />}\n />\n <Flex justify=\"flex-start\">\n <Button\n mode=\"ghost\"\n tone=\"primary\"\n icon={AddIcon}\n text=\"Add Suggestion\"\n fontSize={1}\n onClick={() => handleAddSuggestion('protectedPhrase')}\n />\n </Flex>\n </Stack>\n )\n }\n\n return (\n <Stack space={3}>\n {suggestions.map((suggestion) => {\n const isEditing = editingId === suggestion.id\n const isGlossaryTerm = suggestion.type === 'glossaryTerm'\n const isPrompt = suggestion.type === 'globalPrompt' || suggestion.type === 'localePrompt'\n\n return (\n <Card\n key={suggestion.id}\n padding={4}\n border\n tone={suggestion.approved ? 'default' : 'transparent'}\n style={{ opacity: suggestion.approved ? 1 : 0.5 }}\n >\n <Stack space={3}>\n <Flex align=\"flex-start\" gap={3}>\n <Box paddingTop={1}>\n <Checkbox checked={suggestion.approved} onChange={() => handleToggleApproval(suggestion.id)} />\n </Box>\n\n <Stack space={3} flex={1}>\n <Flex gap={2} align=\"center\" wrap=\"wrap\">\n <Box flex={1} style={{ minWidth: '200px' }}>\n <Select\n fontSize={1}\n value={suggestion.type}\n onChange={(event) =>\n handleTypeChange(suggestion.id, event.currentTarget.value as ImprovementType)\n }\n >\n {Object.entries(IMPROVEMENT_TYPE_LABELS).map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </Select>\n </Box>\n\n <Button\n mode=\"bleed\"\n tone=\"critical\"\n icon={TrashIcon}\n fontSize={1}\n padding={2}\n onClick={() => handleRemove(suggestion.id)}\n />\n </Flex>\n\n {isGlossaryTerm ? (\n <Stack space={2}>\n <Flex gap={2} align=\"center\">\n <Box flex={1}>\n <TextInput\n fontSize={1}\n placeholder=\"Source term\"\n value={suggestion.sourceValue || ''}\n onChange={(event) => handleGlossarySourceChange(suggestion.id, event.currentTarget.value)}\n />\n </Box>\n <Text size={1} muted>\n →\n </Text>\n <Box flex={1}>\n <TextInput\n fontSize={1}\n placeholder=\"Target term\"\n value={suggestion.targetValue || ''}\n onChange={(event) => handleGlossaryTargetChange(suggestion.id, event.currentTarget.value)}\n />\n </Box>\n </Flex>\n </Stack>\n ) : isPrompt ? (\n <Stack space={2}>\n <TextArea\n fontSize={1}\n rows={isEditing ? 6 : 3}\n value={suggestion.description}\n onChange={(event) => handleDescriptionChange(suggestion.id, event.currentTarget.value)}\n onFocus={() => setEditingId(suggestion.id)}\n onBlur={() => setEditingId(null)}\n placeholder=\"Enter prompt guidance...\"\n />\n </Stack>\n ) : (\n <TextInput\n fontSize={1}\n value={suggestion.description}\n onChange={(event) => handleDescriptionChange(suggestion.id, event.currentTarget.value)}\n placeholder=\"Enter protected phrase...\"\n />\n )}\n </Stack>\n </Flex>\n </Stack>\n </Card>\n )\n })}\n\n <Flex justify=\"flex-start\">\n <Button\n mode=\"ghost\"\n tone=\"neutral\"\n icon={AddIcon}\n text=\"Add Suggestion\"\n fontSize={1}\n onClick={() => handleAddSuggestion('protectedPhrase')}\n />\n </Flex>\n </Stack>\n )\n}\n","import { ArrowLeftIcon, EditIcon, InfoOutlineIcon } from '@sanity/icons'\nimport { Box, Button, Card, Checkbox, Flex, Heading, Inline, Stack, Text, TextArea, Tooltip } from '@sanity/ui'\nimport { type FC, useState } from 'react'\nimport { useClient } from 'sanity'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { useTranslationMetadata } from '../hooks/useTranslationMetadata'\nimport type { FeedbackSuggestion } from '../types'\nimport { analyzeFeedback, applySuggestions } from '../utils/processFeedback'\nimport { ProgressPanel } from './ProgressPanel'\nimport { SuggestionReviewList } from './SuggestionReviewList'\n\ninterface GiveFeedbackDialogProps {\n setIsDialogOpen: (isOpen: boolean) => void\n}\n\ntype ProcessingState = 'idle' | 'analyzing' | 'reviewing' | 'applying' | 'completed' | 'error'\n\nexport const GiveFeedbackDialog: FC<GiveFeedbackDialogProps> = ({ setIsDialogOpen }) => {\n const client = useClient({ apiVersion: 'vX' })\n const { document, config, translationMetadata } = useTranslationContext()\n const { loading } = useTranslationMetadata({\n documentId: document._id,\n })\n\n const [feedback, setFeedback] = useState('')\n const [shouldIncludeEdits, setShouldIncludeEdits] = useState(false)\n const [processingState, setProcessingState] = useState<ProcessingState>('idle')\n const [suggestions, setSuggestions] = useState<FeedbackSuggestion[]>([])\n const [changeSummary, setChangeSummary] = useState<string>('')\n const [error, setError] = useState<string>('')\n\n const handleShouldIncludeEditsChange = () => {\n setShouldIncludeEdits(!shouldIncludeEdits)\n }\n\n const handleCancel = () => {\n setIsDialogOpen(false)\n }\n\n const handleAnalyze = async () => {\n if (!feedback && !shouldIncludeEdits) {\n setError('Please provide feedback or enable \"Include Edits\"')\n return\n }\n\n if (!config) {\n setError('Missing plugin configuration')\n return\n }\n\n setError('')\n setProcessingState('analyzing')\n setChangeSummary('')\n\n try {\n const translationHistory = translationMetadata?.translationHistory?.find(\n (history) => history.language === document[config.languageFieldName],\n )\n\n if (!translationHistory) {\n throw new Error(\n 'No translation history found for this document. Please ensure this document was translated using the AI Translation plugin.',\n )\n }\n\n const { sourceSnapshot, targetSnapshot, sourceLanguage } = translationHistory\n\n if (!sourceSnapshot || !targetSnapshot) {\n throw new Error('Translation snapshots are missing from history.')\n }\n\n // Analyze the feedback using the AI agent\n const generatedSuggestions = await analyzeFeedback({\n client,\n schemaId: config.schemaId,\n sourceLanguage: sourceLanguage || 'en-us',\n targetLanguage: document[config.languageFieldName] as string,\n userFeedback: feedback || undefined,\n shouldIncludeEdits,\n sourceSnapshot,\n targetSnapshot,\n currentDocument: shouldIncludeEdits ? document : undefined,\n onProgress: ({ stage, message }) => {\n setProcessingState(stage)\n setChangeSummary(message)\n },\n })\n\n setSuggestions(generatedSuggestions)\n setProcessingState('reviewing')\n } catch (err) {\n console.error('Error analyzing feedback:', err)\n setError(err instanceof Error ? err.message : 'An unexpected error occurred')\n setProcessingState('error')\n }\n }\n\n const handleApplySuggestions = async () => {\n if (!config) {\n setError('Missing plugin configuration')\n return\n }\n\n const approvedCount = suggestions.filter((s) => s.approved).length\n if (approvedCount === 0) {\n setError('Please approve at least one suggestion to apply')\n return\n }\n\n setError('')\n setProcessingState('applying')\n\n try {\n const translationHistory = translationMetadata?.translationHistory?.find(\n (history) => history.language === document[config.languageFieldName],\n )\n\n if (!translationHistory) {\n throw new Error('Translation history not found')\n }\n\n await applySuggestions({\n client,\n schemaId: config.schemaId,\n sourceLanguage: translationHistory.sourceLanguage || 'en-us',\n targetLanguage: translationHistory.language,\n suggestions,\n onProgress: ({ stage, message }) => {\n setProcessingState(stage)\n setChangeSummary(message)\n },\n })\n\n setProcessingState('completed')\n } catch (err) {\n console.error('Error applying suggestions:', err)\n setError(err instanceof Error ? err.message : 'An unexpected error occurred')\n setProcessingState('error')\n }\n }\n\n if (loading) {\n return <ProgressPanel title=\"Loading translation metadata\" />\n }\n\n // Show analyzing state\n if (processingState === 'analyzing') {\n return <ProgressPanel title=\"Analyzing feedback with AI...\" description={changeSummary} />\n }\n\n // Show review state\n if (processingState === 'reviewing') {\n return (\n <Stack space={4}>\n <Stack space={4}>\n <Heading>Review Suggestions</Heading>\n <Text muted>\n The AI has analyzed your feedback and generated the following suggestions. Review and edit them before\n applying.\n </Text>\n </Stack>\n\n <SuggestionReviewList suggestions={suggestions} onSuggestionsChange={setSuggestions} />\n\n {error && (\n <Card padding={3} tone=\"critical\" border>\n <Text size={1}>{error}</Text>\n </Card>\n )}\n\n <Flex justify=\"space-between\" gap={2} paddingTop={2}>\n <Flex gap={2}>\n <Button\n type=\"button\"\n mode=\"bleed\"\n tone=\"neutral\"\n onClick={() => setProcessingState('idle')}\n icon={<ArrowLeftIcon />}\n text=\"Back\"\n />\n </Flex>\n <Button\n type=\"button\"\n mode=\"ghost\"\n tone=\"positive\"\n size={1}\n onClick={handleApplySuggestions}\n disabled={suggestions.filter((s) => s.approved).length === 0}\n >\n Apply {suggestions.filter((s) => s.approved).length} Suggestion\n {suggestions.filter((s) => s.approved).length !== 1 ? 's' : ''}\n </Button>\n </Flex>\n </Stack>\n )\n }\n\n // Show applying state\n if (processingState === 'applying') {\n return <ProgressPanel title=\"Updating translation settings...\" description={changeSummary} icon={<EditIcon />} />\n }\n\n // Show completion state\n if (processingState === 'completed') {\n const appliedCount = suggestions.filter((s) => s.approved).length\n const description = `${appliedCount} suggestion${appliedCount !== 1 ? 's' : ''} applied. Translation prompts and glossary havebeen updated based on your feedback.`\n return (\n <Box padding={4}>\n <ProgressPanel title=\"Translation settings updated\" description={description} status=\"completed\" />\n\n <Flex justify=\"flex-end\" paddingTop={3}>\n <Button type=\"button\" mode=\"ghost\" tone=\"primary\" size={1} onClick={handleCancel}>\n Close\n </Button>\n </Flex>\n </Box>\n )\n }\n\n // Show error state\n if (processingState === 'error') {\n return (\n <Box padding={4}>\n <Stack space={4}>\n <ProgressPanel status=\"error\" title=\"Error processing feedback\" description={error} tone=\"critical\" />\n <Flex justify=\"flex-end\" gap={2}>\n <Button type=\"button\" mode=\"ghost\" onClick={handleCancel}>\n Close\n </Button>\n <Button type=\"reset\" mode=\"ghost\" tone=\"primary\" onClick={() => setProcessingState('idle')}>\n Reset\n </Button>\n </Flex>\n </Stack>\n </Box>\n )\n }\n\n // Default form view\n return (\n <Stack space={4}>\n <Card tone=\"transparent\" padding={4}>\n <Stack space={4}>\n <Stack space={2}>\n <Stack space={4}>\n <Inline space={2}>\n <Text size={2} muted>\n Enter your feedback for the translation AI agent.\n </Text>\n <Tooltip\n portal\n content={\n <Box padding={2} style={{ maxWidth: '280px' }}>\n <Text size={1}>\n The AI agent will use your feedback to improve translation prompts, update protected phrases,\n and modify the glossary. Be specific about what should be changed.\n </Text>\n </Box>\n }\n >\n <Text size={1}>\n <InfoOutlineIcon />\n </Text>\n </Tooltip>\n </Inline>\n <TextArea\n rows={8}\n fontSize={2}\n onChange={(event) => setFeedback(event.currentTarget.value)}\n padding={3}\n placeholder='Example: \"Braze\" is a branded term and should not be translated.'\n value={feedback}\n />\n </Stack>\n </Stack>\n\n <Stack space={2}>\n <Stack space={3}>\n <Button\n type=\"button\"\n mode={shouldIncludeEdits ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleShouldIncludeEditsChange}\n tone={shouldIncludeEdits ? 'primary' : 'default'}\n >\n <Flex align=\"flex-start\" gap={3}>\n <Box paddingTop={1}>\n <Checkbox checked={shouldIncludeEdits} readOnly style={{ pointerEvents: 'none' }} />\n </Box>\n <Stack space={2} flex={1}>\n <Text size={2} weight=\"medium\">\n Include Edits in Feedback\n </Text>\n <Text size={1} muted style={{ textAlign: 'left' }}>\n The AI will analyze edits you made to the translation.\n </Text>\n </Stack>\n </Flex>\n </Button>\n </Stack>\n </Stack>\n </Stack>\n </Card>\n <Flex justify=\"flex-end\" gap={2} paddingTop={2}>\n <Button type=\"button\" mode=\"ghost\" size={1} onClick={handleCancel}>\n Cancel\n </Button>\n <Button\n type=\"submit\"\n mode=\"ghost\"\n tone=\"positive\"\n size={1}\n onClick={handleAnalyze}\n disabled={!feedback.trim() && !shouldIncludeEdits}\n >\n Analyze Feedback\n </Button>\n </Flex>\n </Stack>\n )\n}\n","import defaults from 'lodash.defaults'\nimport type { TranslationAction, TranslationContext } from '../../types'\nimport { devLog } from '../../utils/devLog'\n\nexport const translationReducer = (\n context: Omit<TranslationContext, 'dispatch'>,\n action: TranslationAction,\n): Omit<TranslationContext, 'dispatch'> => {\n const logContext = {\n documentId: context.document?._id,\n actionType: action.type,\n component: 'translationReducer',\n }\n\n devLog.debug('Translation action dispatched', {\n ...logContext,\n payload: action.payload,\n })\n\n switch (action.type) {\n case 'SET_OVERALL_STATUS':\n return { ...context, overallStatus: action.payload }\n\n case 'SET_TRANSLATION_METADATA':\n return { ...context, translationMetadata: action.payload }\n\n case 'SET_SELECTED_TARGET_LANGUAGES':\n return {\n ...context,\n selectedTargetLanguages: action.payload,\n }\n\n case 'SET_SHOULD_TRANSLATE_DIFFS':\n return {\n ...context,\n shouldTranslateDiffs: action.payload,\n }\n\n case 'SET_SHOULD_TRANSLATE_REFERENCES':\n return {\n ...context,\n shouldTranslateReferences: action.payload,\n }\n\n case 'SET_MAX_REFERENCE_DEPTH':\n return {\n ...context,\n maxReferenceDepth: action.payload,\n }\n\n case 'SET_SHOULD_OVERWRITE_FRESH_TRANSLATIONS':\n return {\n ...context,\n shouldOverwriteFreshTranslations: action.payload,\n }\n\n case 'SET_REFERENCES':\n return {\n ...context,\n references: action.payload,\n }\n\n case 'SET_TRANSLATION_JOB_STATUS': {\n // Create a unique key for each job using both document ID and language\n // This ensures concurrent translations to different languages don't conflict\n const jobKey = `${action.payload._id}_${action.payload.language}`\n\n // Create a new Map to trigger React re-render (immutability)\n const newTranslationJobs = new Map(context.translationJobs)\n\n newTranslationJobs.set(jobKey, defaults(action.payload, newTranslationJobs.get(jobKey)))\n\n return {\n ...context,\n translationJobs: newTranslationJobs,\n }\n }\n\n default:\n return context\n }\n}\n","import { type FC, useReducer } from 'react'\nimport type { PluginConfig, TranslatableDocument, TranslationContext as TTranslationContext } from '../../types'\nimport { devLog } from '../../utils/devLog'\nimport { TranslationContext } from './TranslationContext'\nimport { translationReducer } from './translationReducer'\n\ninterface TranslationContextProviderProps {\n document: TranslatableDocument\n config: PluginConfig\n children: React.ReactNode\n}\n\nexport const TranslationContextProvider: FC<TranslationContextProviderProps> = ({ document, config, children }) => {\n devLog.debug('TranslationContextProvider initialized', {\n documentId: document._id,\n documentType: document._type,\n supportedLanguages: config.supportedLanguages?.map((l) => l.id),\n component: 'TranslationContextProvider',\n })\n\n const initialContext: Omit<TTranslationContext, 'dispatch'> = {\n document,\n config,\n overallStatus: 'idle',\n translationMetadata: null,\n selectedTargetLanguages: [],\n shouldTranslateDiffs: false,\n shouldOverwriteFreshTranslations: false,\n shouldTranslateReferences: false,\n maxReferenceDepth: 1,\n references: [],\n translationJobs: new Map(),\n }\n\n const [context, dispatch] = useReducer(translationReducer, initialContext)\n\n devLog.debug('Translation context state initialized', {\n documentId: document._id,\n overallStatus: context.overallStatus,\n selectedLanguages: context.selectedTargetLanguages,\n shouldTranslateDiffs: context.shouldTranslateDiffs,\n component: 'TranslationContextProvider',\n })\n\n return <TranslationContext.Provider value={{ ...context, dispatch }}>{children}</TranslationContext.Provider>\n}\n","import { TranslateIcon } from '@sanity/icons'\nimport { useState } from 'react'\nimport type { DocumentActionDescription, DocumentActionProps } from 'sanity'\nimport { GiveFeedbackDialog } from './components/GiveFeedbackDialog'\nimport { TranslationContextProvider } from './hooks/useTranslationContext/TranslationContextProvider'\nimport type { PluginConfig, TranslatableDocument } from './types'\nimport { devLog } from './utils/devLog'\n\ninterface TranslateActionProps extends DocumentActionProps {\n config: PluginConfig\n}\n\nexport const getGiveTranslationFeedbackAction = (config: PluginConfig) => {\n return ({ draft, published }: TranslateActionProps): DocumentActionDescription | null => {\n const document = draft ?? published\n const [isDialogOpen, setIsDialogOpen] = useState(false)\n\n devLog.debug('ImproveTranslationPromptsAction initialized', {\n documentId: document?._id,\n documentType: document?._type,\n })\n\n if (!document || !config.translatableSchemaTypes?.includes(document._type)) {\n devLog.warn('Document not in translatable schema types', {\n documentType: document?._type,\n translatableTypes: config.translatableSchemaTypes,\n })\n return null\n }\n\n if (!config) {\n devLog.error('Missing config in TranslateAction')\n return null\n }\n\n return {\n label: 'Give Translation Feedback',\n icon: TranslateIcon,\n onHandle: () => {\n devLog.info('Give Translation Feedback dialog opened', {\n documentId: document._id,\n documentType: document._type,\n component: 'GiveTranslationFeedbackAction',\n })\n setIsDialogOpen(true)\n },\n dialog: isDialogOpen && {\n type: 'dialog',\n onClose: () => setIsDialogOpen(false),\n header: 'Give Translation Feedback',\n content: (\n <TranslationContextProvider document={document as TranslatableDocument} config={config}>\n <GiveFeedbackDialog setIsDialogOpen={setIsDialogOpen} />\n </TranslationContextProvider>\n ),\n },\n }\n }\n}\n","import { TranslateIcon } from '@sanity/icons'\nimport { defineField, defineType } from 'sanity'\n\nexport const translationGlossaryTerm = defineType({\n name: 'translationGlossaryTerm',\n title: 'Translation Glossary Term',\n icon: TranslateIcon,\n type: 'document',\n fields: [\n defineField({\n name: 'translations',\n title: 'Translations',\n type: 'internationalizedArrayString',\n }),\n ],\n preview: {\n select: {\n translations: 'translations',\n },\n prepare({ translations }: { translations: { locale: string; value: string }[] }) {\n const enTranslation = translations?.find((t) => t.locale === 'en-us')\n const firstTranslation = translations?.[0]\n return {\n title: enTranslation?.value || firstTranslation?.value || 'No translation available',\n }\n },\n },\n})\n","import { defineField } from 'sanity'\n\nexport const translationHistory = defineField({\n name: 'translationHistory',\n type: 'array',\n of: [\n {\n name: 'targetLanguageHistory',\n type: 'object',\n fields: [\n defineField({\n name: 'language',\n title: 'Language',\n description: 'The language of the target document',\n type: 'string',\n }),\n defineField({\n name: 'sourceId',\n title: 'Source ID',\n description: 'The ID of the source document',\n type: 'string',\n }),\n defineField({\n name: 'sourceRev',\n title: 'Source Revision',\n description: 'The revision ID of the source document at the time of translation',\n type: 'string',\n }),\n defineField({\n name: 'sourceLanguage',\n title: 'Source Language',\n description: 'The language of the source document',\n type: 'string',\n }),\n defineField({\n name: 'sourceSnapshot',\n title: 'Source Snapshot',\n description: 'The snapshot of the source document at the time of translation',\n type: 'text',\n }),\n defineField({\n name: 'targetId',\n title: 'Target ID',\n description: 'The ID of the target document',\n type: 'string',\n }),\n ],\n },\n ],\n})\n","import { TranslateIcon } from '@sanity/icons'\nimport { defineField, defineType } from 'sanity'\n\nexport const translationSettings = defineType({\n name: 'translationSettings',\n title: 'Translation Settings',\n icon: TranslateIcon,\n type: 'document',\n fields: [\n defineField({\n name: 'globalPrompt',\n title: 'Global Translation Prompt',\n description: 'A prompt that will given to the Sanity AI Agent for all translation tasks.',\n type: 'text',\n rows: 5,\n }),\n defineField({\n name: 'localePrompts',\n title: 'Locale Prompts',\n description: 'Prompts that will be given to the Sanity AI Agent for each locale.',\n type: 'internationalizedArrayText',\n }),\n defineField({\n name: 'protectedPhrases',\n title: 'Protected Phrases',\n description: 'Phrases that will never be translated.',\n type: 'array',\n of: [{ type: 'string' }],\n }),\n ],\n preview: {\n prepare: () => ({\n title: 'Translation Settings',\n }),\n },\n})\n","import type { SanityClient } from 'sanity'\nimport type { TranslatableDocument, TranslationGlossaryTermDocument, TranslationSettingsDocument } from '../types'\n\ninterface FetchTranslationPromptsOptions {\n client: SanityClient\n sourceLanguage?: string\n sourceDocument?: TranslatableDocument\n targetLanguages: Array<string>\n}\n\nexport interface FetchTranslationPromptsResult {\n globalPrompt?: string\n protectedPhrases?: Array<string>\n localeInstructions: Record<\n string,\n {\n prompt?: string\n glossaryTerms?: string\n }\n >\n}\n\nexport const fetchTranslationPrompts = async ({\n client,\n sourceLanguage,\n sourceDocument,\n targetLanguages,\n}: FetchTranslationPromptsOptions): Promise<FetchTranslationPromptsResult> => {\n const sourceDocumentString = JSON.stringify(sourceDocument)\n\n const translationSettings = await client.fetch<TranslationSettingsDocument | null>(\n `*[_id == \"translation-settings\"][0] {\n globalPrompt,\n localePrompts[locale in $targetLanguages],\n protectedPhrases\n }`,\n { targetLanguages },\n )\n\n // Fetch all translation glossary terms that have a translation in both the source and target languages\n const translationGlossaryTerms =\n (await client.fetch<Array<NonNullable<TranslationGlossaryTermDocument['translations']>> | null>(\n `*[\n _type == \"translationGlossaryTerm\"\n && count(translations[_key in $targetLanguages]) > 0\n && count(translations[_key == $sourceLanguage]) > 0\n ].translations`,\n { targetLanguages, sourceLanguage },\n )) || []\n\n console.log('translationGlossaryTerms', translationGlossaryTerms)\n\n const glossaryTermsByLocale: Record<string, Array<{ from: string; to: string }>> = {}\n\n for (const targetLanguage of targetLanguages) {\n const relevantTerms = translationGlossaryTerms.filter((termTranslations) =>\n termTranslations.some((translation) => translation._key === targetLanguage),\n )\n\n let relevantTranslations = relevantTerms\n .map((termTranslations) => {\n const from = termTranslations.find((translation) => translation._key === sourceLanguage)?.value\n const to = termTranslations.find((translation) => translation._key === targetLanguage)?.value\n if (!from || !to) {\n return null\n }\n return { from, to }\n })\n .filter((item): item is { from: string; to: string } => item !== null) // brow-beating the Typescript compiler since `filter(Boolean)` doesn't register correctly// brow-beating the Typescript compiler since `filter(Boolean)` doesn't register correctly\n\n console.log('relevantTranslations', relevantTranslations)\n\n // Filter to only include terms that appear in the source document\n if (sourceDocument) {\n relevantTranslations = relevantTranslations.filter(({ from }) =>\n termAppearsInDocument(from, sourceDocumentString),\n )\n console.log('relevantTranslations', relevantTranslations)\n }\n\n glossaryTermsByLocale[targetLanguage] = relevantTranslations\n }\n\n return {\n globalPrompt: translationSettings?.globalPrompt,\n protectedPhrases: translationSettings?.protectedPhrases,\n localeInstructions: Object.fromEntries(\n targetLanguages.map((locale) => [\n locale,\n {\n prompt: translationSettings?.localePrompts?.find((lp) => lp._key === locale)?.value,\n glossaryTerms: formatGlossaryTermInstruction(glossaryTermsByLocale[locale]),\n },\n ]),\n ),\n }\n}\n\n/**\n * Checks if a term appears anywhere in the document content.\n * Stringifies the document and performs a case-insensitive search.\n */\nconst termAppearsInDocument = (term: string, documentString: string): boolean => {\n // Handle colon-delimited terms by checking the base term (before the colon)\n const baseTerm = term.split(':')[0].trim()\n\n return documentString.includes(baseTerm.toLowerCase())\n}\n\nconst formatGlossaryTermInstruction = (terms: Array<{ from: string; to: string }>) => {\n const instructions = [\n '## Glossary Terms',\n 'Translate the following terms exactly as described below.',\n 'When a term includes a colon, the suffix following the colon describes how the term should be translated for the female gender.',\n ]\n\n terms.forEach(({ from, to }) => {\n instructions.push(`Always translate \"${from}\" to \"${to}\".`)\n })\n\n return instructions.join('\\n')\n}\n","export type RecursiveSearchable =\n | null\n | undefined\n | string\n | number\n | boolean\n | RecursiveSearchable[]\n | { [key: string]: RecursiveSearchable }\n\nexport type FindKeyValueResult<T = unknown> = {\n value: T\n path: Array<string | number>\n}\n\n/**\n * Recursively searches through an object/array structure to find all values\n * associated with a specific key name, along with their paths.\n *\n * @param obj - The object or array to search through\n * @param targetKey - The key name to search for\n * @returns An array of objects containing the value and path for each occurrence of the target key\n */\nexport const findKeyValues = <T = unknown>(obj: RecursiveSearchable, targetKey: string): FindKeyValueResult<T>[] => {\n const results: FindKeyValueResult<T>[] = []\n\n const recursiveSearch = (current: RecursiveSearchable, currentPath: Array<string | number>): void => {\n // Handle null/undefined\n if (current === null || current === undefined) {\n return\n }\n\n // If current item is an array, search each element\n if (Array.isArray(current)) {\n current.forEach((item, index) => {\n recursiveSearch(item, [...currentPath, index])\n })\n return\n }\n\n // If current item is an object\n if (typeof current === 'object') {\n for (const [key, value] of Object.entries(current)) {\n const newPath = [...currentPath, key]\n\n // If we found the target key, add its value and path to our results\n if (key === targetKey) {\n results.push({\n value: value as T,\n path: newPath,\n })\n }\n\n // Continue searching recursively\n recursiveSearch(value, newPath)\n }\n }\n }\n\n recursiveSearch(obj, [])\n return results\n}\n","import { pathToString, type SanityClient } from 'sanity'\nimport { TRANSLATION_METADATA_TYPE } from '../consts'\nimport type { PluginConfig } from '../types'\nimport { type FindKeyValueResult, findKeyValues } from './findKeyValues'\nimport { undraftId } from './undraftId'\n\ninterface LocalizeReferenceParams {\n client: SanityClient\n documentId: string\n languageFieldName: PluginConfig['languageFieldName']\n}\n\nexport const localizeReferences = async ({ client, documentId, languageFieldName }: LocalizeReferenceParams) => {\n try {\n const doc = await client.fetch('*[_id == $documentId][0]', { documentId })\n\n if (!doc) {\n console.error(documentId, 'not found')\n return\n }\n\n const targetLanguage = doc[languageFieldName]\n\n if (!targetLanguage) {\n console.error(documentId, 'no value found for language field:', languageFieldName)\n return\n }\n\n const refs = findKeyValues<string>(doc, '_ref')\n\n if (!refs?.length) {\n return\n }\n\n await updateReferences(documentId, client, refs, targetLanguage)\n } catch (error) {\n console.error('Error localizing references:', error)\n }\n}\n\nexport const updateReferences = async (\n documentId: string,\n client: SanityClient,\n refs: Array<FindKeyValueResult<string>>,\n targetLanguage: string,\n) => {\n const patch = client.patch(documentId)\n\n if (!refs?.length) {\n return []\n }\n\n for (const ref of refs) {\n const newId = await client.fetch<string | null>(\n '(*[_type == $translationMetadataSchemaType && references($sourceId)].translations[_key == $targetLanguage].value._ref)[0]',\n {\n translationMetadataSchemaType: TRANSLATION_METADATA_TYPE,\n sourceId: undraftId(ref.value),\n targetLanguage,\n },\n )\n\n if (!newId) {\n // No matching translation found for the reference. The document might not have been translated yet\n // or might not be of a translatable schema type.\n continue\n }\n\n patch.set({ [pathToString(ref.path)]: undraftId(newId) })\n patch.set({ [`${pathToString(ref.path.slice(0, -1))}._weak`]: true })\n patch.set({\n [`${pathToString(ref.path.slice(0, -1))}._strengthenOnPublish`]: {\n _type: 'reference',\n _weak: false,\n },\n })\n\n await patch.commit()\n }\n}\n","/**\n * Semaphore class for rate limiting concurrent operations\n * Ensures that only a specified number of operations can run simultaneously\n */\nexport class Semaphore {\n private permits: number\n private queue: Array<() => void> = []\n\n constructor(permits: number) {\n this.permits = permits\n }\n\n /**\n * Acquire a permit from the semaphore\n * If no permits are available, the caller will wait until one becomes available\n */\n async acquire(): Promise<void> {\n if (this.permits > 0) {\n this.permits--\n return Promise.resolve()\n }\n\n // Wait for a permit to become available\n return new Promise<void>((resolve) => {\n this.queue.push(resolve)\n })\n }\n\n /**\n * Release a permit back to the semaphore\n * If there are waiting callers, one will be woken up\n */\n release(): void {\n const next = this.queue.shift()\n if (next) {\n // Give the permit to the next waiting caller\n next()\n } else {\n // No one is waiting, increment the available permits\n this.permits++\n }\n }\n\n /**\n * Execute a function with semaphore protection\n * Automatically acquires and releases the permit\n */\n async withPermit<T>(fn: () => Promise<T>): Promise<T> {\n await this.acquire()\n try {\n return await fn()\n } finally {\n this.release()\n }\n }\n\n /**\n * Get the number of available permits\n */\n availablePermits(): number {\n return this.permits\n }\n\n /**\n * Get the number of waiting callers\n */\n queueLength(): number {\n return this.queue.length\n }\n\n /**\n * Update the number of permits\n * If increasing permits, waiting callers will be notified\n * If decreasing permits below current available, available permits will be reduced\n */\n updatePermits(newPermits: number): void {\n const currentTotal = this.permits + this.queue.length\n const difference = newPermits - currentTotal\n\n if (difference > 0) {\n // Increasing permits - wake up waiting callers or add to available permits\n for (let i = 0; i < difference && this.queue.length > 0; i++) {\n const next = this.queue.shift()\n if (next) next()\n }\n // Add any remaining permits to available count\n const remainingIncrease = difference - (currentTotal - this.permits - this.queue.length)\n if (remainingIncrease > 0) {\n this.permits += remainingIncrease\n }\n } else if (difference < 0) {\n // Decreasing permits - reduce available permits (but don't interrupt running operations)\n this.permits = Math.max(0, this.permits + difference)\n }\n }\n}\n","import type { Dispatch } from 'react'\nimport type { SetTranslationJobStatusAction, TranslationAction } from '../types'\n\nexport const setupTranslationJobStatuses = (\n dispatch: Dispatch<TranslationAction>,\n sourceDocuments: Array<{\n _id: string\n _type: string\n title?: string\n }>,\n targetLanguages: Array<string>,\n) => {\n for (const sourceDocument of sourceDocuments) {\n for (const lang of targetLanguages) {\n const payload: SetTranslationJobStatusAction['payload'] = {\n _id: sourceDocument._id,\n _type: sourceDocument._type,\n language: lang,\n status: 'queued',\n title: sourceDocument.title,\n }\n\n dispatch({\n type: 'SET_TRANSLATION_JOB_STATUS',\n payload,\n })\n }\n }\n}\n","import type { PluginConfig, TranslationMetadataDocument } from '../types'\n\nexport const getExistingTranslationId = (\n translationMetadata: TranslationMetadataDocument,\n targetLanguage: PluginConfig['supportedLanguages'][number]['id'],\n): string | null => {\n if (!translationMetadata?.translations?.length) {\n return null\n }\n\n const existingTranslation = translationMetadata.translations.find(\n (translation) => translation._key === targetLanguage,\n )\n\n return existingTranslation?.value._ref || null\n}\n","import type { PluginConfig, TranslationMetadataDocument } from '../types'\nimport { getExistingTranslationId } from './getExistingTranslationId'\n\ninterface DetermineTranslationTargetParams {\n translationMetadata: TranslationMetadataDocument\n targetLanguage: PluginConfig['supportedLanguages'][number]['id']\n}\n\nexport const determineTranslationTarget = ({\n translationMetadata,\n targetLanguage,\n}: DetermineTranslationTargetParams) => {\n const existingTranslationId = getExistingTranslationId(translationMetadata, targetLanguage)\n\n return existingTranslationId\n ? {\n // Update existing translation\n operation: 'createOrReplace' as const,\n _id: existingTranslationId,\n }\n : {\n // Create new translation\n operation: 'create' as const,\n }\n}\n","import type { SanityClient } from 'sanity'\nimport { TRANSLATION_METADATA_TYPE } from '../consts'\nimport type { TranslatableDocument, TranslationMetadataDocument } from '../types'\nimport { undraftId } from './undraftId'\n\ninterface PrepareTranslationMetadataParams {\n client: SanityClient\n sourceDocument: TranslatableDocument\n sourceLanguage: string\n}\n\nexport const getTranslationMetadata = async ({\n client,\n sourceDocument,\n sourceLanguage,\n}: PrepareTranslationMetadataParams): Promise<TranslationMetadataDocument> => {\n try {\n const existingDoc = await client.fetch<TranslationMetadataDocument | null>(\n '*[_type == $tmType && references($sourceDocumentId)][0]',\n {\n tmType: TRANSLATION_METADATA_TYPE,\n sourceDocumentId: undraftId(sourceDocument._id),\n },\n )\n\n if (existingDoc) {\n return existingDoc\n }\n\n const newDoc = (await client.create({\n _type: TRANSLATION_METADATA_TYPE,\n translations: [\n {\n _key: sourceLanguage,\n _type: 'internationalizedArrayReferenceValue',\n value: {\n _type: 'reference',\n _ref: undraftId(sourceDocument._id),\n _weak: true,\n _strengthenOnPublish: {\n _type: sourceDocument._type,\n _weak: false,\n },\n },\n },\n ],\n translationHistory: [],\n })) as TranslationMetadataDocument\n\n return newDoc\n } catch (error) {\n console.error(sourceDocument._id, 'Error creating translation metadata:', error)\n throw error\n }\n}\n","import defaults from 'lodash.defaults'\nimport type { Dispatch } from 'react'\nimport type { SetTranslationJobStatusAction, TranslationAction, TranslationJob } from '../types'\n\nexport const setJobStatus = (\n dispatch: Dispatch<TranslationAction>,\n _id: string,\n language: string,\n status: TranslationJob['status'],\n payload?: Partial<SetTranslationJobStatusAction['payload']>,\n) => {\n dispatch({\n type: 'SET_TRANSLATION_JOB_STATUS',\n payload: defaults(payload, {\n _id,\n language,\n status,\n }),\n })\n}\n","import type { SanityPatchMutation } from '@sanity/diff-patch'\nimport type { Dispatch } from 'react'\nimport type { SanityClient, SanityDocument } from 'sanity'\nimport type { TranslationAction } from '../types'\nimport { setJobStatus } from './setJobStatus'\n\ninterface TranslateDocumentInPlaceParams {\n client: SanityClient\n schemaId: string\n dispatch: Dispatch<TranslationAction>\n sourceDocument: SanityDocument\n languageFieldName: string\n targetLanguage: string\n targetId: string\n patch: Array<SanityPatchMutation>\n}\n\nexport const translateDocumentInPlace = async ({\n client,\n schemaId,\n dispatch,\n sourceDocument,\n languageFieldName,\n targetLanguage,\n targetId,\n patch,\n}: TranslateDocumentInPlaceParams) => {\n try {\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'translating')\n\n const updatedDocument = await client.agent.action.translate({\n schemaId,\n documentId: targetId,\n toLanguage: {\n title: targetLanguage,\n id: targetLanguage,\n },\n fromLanguage: {\n title: sourceDocument[languageFieldName] as string,\n id: sourceDocument[languageFieldName] as string,\n },\n languageFieldPath: [languageFieldName],\n styleGuide: `\n\t\t\t **IMPORTANT:** Much of this document is already translated into the target language. The original version of this document in the source language\n\t\t\t\twas updated. The following patch instruction shows precisely how the source document was edited: $patchInstruction. Your job is to update this\n\t\t\t translation to including matching changes.\n\t\t\t\t`,\n styleGuideParams: {\n patchInstruction: JSON.stringify(patch, null, 2),\n },\n })\n\n return updatedDocument as SanityDocument\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'error', {\n errorMessage,\n })\n console.error('Error translating document:', error)\n // Return undefined instead of throwing to allow other translations to continue\n return undefined\n }\n}\n","import type { TranslatableDocument } from '../types'\n\ninterface AssembleLanguageSpecsParams {\n sourceDocument: TranslatableDocument\n languageFieldName: string\n targetLanguage: string\n}\n\nexport const assembleLanguageSpecs = ({\n sourceDocument,\n languageFieldName,\n targetLanguage,\n}: AssembleLanguageSpecsParams): {\n toLanguage: { id: string; title: string }\n fromLanguage: { id: string; title: string }\n} => {\n const sourceLanugageId = sourceDocument[languageFieldName] as string | undefined\n\n if (!sourceLanugageId) {\n throw new Error('[assembleLanguages] Source language ID is missing')\n }\n\n return {\n fromLanguage: {\n id: sourceLanugageId,\n title: sourceLanugageId,\n },\n toLanguage: {\n id: targetLanguage,\n title: targetLanguage,\n },\n }\n}\n","import type { Dispatch } from 'react'\nimport type { SanityClient, SanityDocument } from 'sanity'\nimport { UPDATE_EXISTING_TRANSLATION_PROMPT } from '../consts'\nimport type { TranslatableDocument, TranslationAction } from '../types'\nimport { assembleLanguageSpecs } from './assembleLanguageSpecs'\nimport type { determineTranslationTarget } from './determineTranslationTarget'\nimport { devLog } from './devLog'\nimport type { FetchTranslationPromptsResult } from './fetchTranslationPrompts'\nimport { setJobStatus } from './setJobStatus'\nimport { draftId, undraftId } from './undraftId'\n\ninterface TranslateEntireDocumentOptions {\n dispatch: Dispatch<TranslationAction>\n client: SanityClient\n schemaId: string\n sourceDocument: TranslatableDocument\n targetLanguage: string\n languageFieldName: string\n translationTarget: ReturnType<typeof determineTranslationTarget>\n translationPrompts: FetchTranslationPromptsResult\n}\n\nexport const translateEntireDocument = async ({\n dispatch,\n client,\n schemaId,\n sourceDocument,\n targetLanguage,\n languageFieldName,\n translationTarget,\n translationPrompts,\n}: TranslateEntireDocumentOptions) => {\n const logContext = {\n documentId: sourceDocument._id,\n targetLanguage,\n schemaId,\n operation: translationTarget.operation,\n targetId: translationTarget._id,\n }\n\n devLog.group('translateEntireDocument', logContext)\n devLog.time('translateEntireDocument')\n\n try {\n // Assemble specs to tell the Sanity agent how to translate the document\n const { toLanguage, fromLanguage } = assembleLanguageSpecs({\n sourceDocument,\n languageFieldName,\n targetLanguage,\n })\n\n devLog.debug('Language specs assembled', {\n ...logContext,\n toLanguage,\n fromLanguage,\n })\n\n let extantTranslation = ''\n if (translationTarget._id) {\n devLog.debug('Checking for existing translation', {\n ...logContext,\n targetId: translationTarget._id,\n })\n\n extantTranslation = await client\n .withConfig({\n perspective: 'raw',\n })\n .fetch(`*[_id in $ids] | order((_id match \"drafts*\") desc)[0]._id`, {\n ids: [undraftId(translationTarget._id), draftId(translationTarget._id)],\n })\n\n devLog.info('Extant translation found - will preserve existing content where possible', {\n ...logContext,\n hasExtantTranslation: !!extantTranslation,\n })\n }\n\n // Ask the Sanity agent to translate the document\n devLog.info('Starting Sanity agent translation', logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'translating')\n\n const styleGuide = [\n translationPrompts.globalPrompt,\n translationPrompts.localeInstructions[targetLanguage]?.prompt,\n translationPrompts.localeInstructions[targetLanguage]?.glossaryTerms,\n extantTranslation ? UPDATE_EXISTING_TRANSLATION_PROMPT : null,\n ]\n .filter(Boolean)\n .join('\\n\\n')\n\n devLog.info('Style guide generated', {\n ...logContext,\n styleGuide,\n })\n\n const newDocument = (await client.agent.action.translate({\n schemaId,\n toLanguage,\n fromLanguage,\n documentId: sourceDocument._id,\n targetDocument: translationTarget,\n languageFieldPath: [languageFieldName],\n styleGuide,\n styleGuideParams: {\n extantTranslation,\n },\n protectedPhrases: translationPrompts.protectedPhrases || [],\n conditionalPaths: {\n defaultHidden: false,\n defaultReadOnly: false,\n },\n })) as SanityDocument\n\n devLog.info('Document translation completed', {\n ...logContext,\n newDocumentId: newDocument._id,\n newDocumentRev: newDocument._rev,\n })\n\n devLog.timeEnd('translateEntireDocument')\n devLog.groupEnd()\n return newDocument\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n devLog.error(\n 'translateEntireDocument failed',\n error instanceof Error ? error : new Error(String(error)),\n logContext,\n )\n\n // Set error status with message\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'error', {\n errorMessage,\n })\n\n devLog.timeEnd('translateEntireDocument')\n devLog.groupEnd()\n // Return undefined instead of throwing to allow other translations to continue\n return undefined\n }\n}\n","import type { SanityClient, SanityDocument } from 'sanity'\nimport type { TranslationMetadataDocument } from '../types'\nimport { undraftId } from './undraftId'\n\ninterface UpdateTranslationMetadataParams {\n client: SanityClient\n sourceDocument: SanityDocument\n sourceLanguage: string\n newDocument: SanityDocument\n targetLanguage: string\n translationMetadata: TranslationMetadataDocument\n isNewTranslation: boolean\n}\n\nexport const updateTranslationMetadata = async ({\n client,\n targetLanguage,\n sourceDocument,\n sourceLanguage,\n newDocument,\n translationMetadata,\n isNewTranslation,\n}: UpdateTranslationMetadataParams) => {\n try {\n const refToNewTranslation: TranslationMetadataDocument['translations'][number] = {\n _key: targetLanguage,\n _type: 'internationalizedArrayReferenceValue',\n value: {\n _type: 'reference',\n _ref: undraftId(newDocument._id),\n _weak: true,\n _strengthenOnPublish: {\n _type: 'reference',\n _weak: false,\n },\n },\n }\n\n const newTranslationHistory: TranslationMetadataDocument['translationHistory'][number] = {\n _key: targetLanguage,\n language: targetLanguage,\n sourceId: undraftId(sourceDocument._id),\n sourceRev: sourceDocument._rev,\n sourceLanguage,\n sourceSnapshot: JSON.stringify(sourceDocument),\n targetId: newDocument._id,\n targetRev: newDocument._rev,\n targetSnapshot: JSON.stringify(newDocument),\n }\n\n const translationPatch = client\n .patch(translationMetadata._id)\n // If there is no value set for `translations`, set it to an empty array\n .setIfMissing({ translations: [] })\n\n if (isNewTranslation) {\n await translationPatch.insert('after', 'translations[-1]', [refToNewTranslation]).commit()\n } else {\n await translationPatch\n .insert('replace', `translations[_key == \"${targetLanguage}\"]`, [refToNewTranslation])\n .commit()\n }\n\n const historyPatch = client.patch(translationMetadata._id).setIfMissing({ translationHistory: [] })\n const translationHistoryExists = !!translationMetadata.translationHistory?.some(\n (history) => history.language === targetLanguage,\n )\n\n if (!translationHistoryExists) {\n await historyPatch.insert('after', 'translationHistory[-1]', [newTranslationHistory]).commit()\n } else {\n await historyPatch\n .insert('replace', `translationHistory[_key == \"${targetLanguage}\"]`, [newTranslationHistory])\n .commit()\n }\n } catch (error) {\n console.error('Error updating translation metadata:', error)\n throw error\n }\n}\n","import { diffPatch } from '@sanity/diff-patch'\nimport type { Dispatch } from 'react'\nimport type { SanityClient, SanityDocument } from 'sanity'\nimport type { PluginConfig, TranslatableDocument, TranslationAction, TranslationMetadataDocument } from '../types'\nimport { determineTranslationTarget } from './determineTranslationTarget'\nimport { devLog } from './devLog'\nimport type { FetchTranslationPromptsResult } from './fetchTranslationPrompts'\nimport { getTranslationMetadata } from './getTranslationMetadata'\nimport { setJobStatus } from './setJobStatus'\nimport { translateDocumentInPlace } from './translateDocumentInPlace'\nimport { translateEntireDocument } from './translateEntireDocument'\nimport { draftId, undraftId } from './undraftId'\nimport { updateTranslationMetadata } from './updateTranslationMetadata'\n\ninterface TranslateDocumentParams {\n dispatch: Dispatch<TranslationAction>\n client: SanityClient\n sourceDocument: TranslatableDocument\n targetLanguage: PluginConfig['supportedLanguages'][number]['id']\n languageFieldName: PluginConfig['languageFieldName']\n shouldOverwriteFreshTranslations: boolean\n schemaId: string\n shouldTranslateDiffs: boolean\n translationPrompts: FetchTranslationPromptsResult\n}\n\nexport const translateDocument = async ({\n dispatch,\n client,\n sourceDocument,\n targetLanguage,\n languageFieldName,\n shouldOverwriteFreshTranslations,\n schemaId,\n shouldTranslateDiffs,\n translationPrompts,\n}: TranslateDocumentParams) => {\n const logContext = {\n documentId: sourceDocument._id,\n targetLanguage,\n schemaId,\n shouldTranslateDiffs,\n shouldOverwriteFreshTranslations,\n }\n\n devLog.group('translateDocument', logContext)\n devLog.time('translateDocument')\n\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'preparing_translation')\n\n try {\n // Confirm that source document has a language\n const sourceLanguage = sourceDocument[languageFieldName] as string | undefined\n\n devLog.debug('Checking source document language', {\n ...logContext,\n sourceLanguage,\n languageFieldName,\n })\n\n if (!sourceLanguage) {\n const error = `Source document ${sourceDocument._id} does not have a language`\n devLog.error(error, undefined, logContext)\n throw new Error(error)\n }\n\n // Get the translation metadata for the document, creating it if necessary\n devLog.debug('Getting translation metadata', logContext)\n const translationMetadata = await getTranslationMetadata({\n client,\n sourceDocument,\n sourceLanguage,\n })\n\n const isAlreadyFreshTranslation =\n translationMetadata.translationHistory?.some(\n (history) => history.language === targetLanguage && history.sourceRev === sourceDocument._rev,\n ) ?? false\n\n devLog.debug('Checking if translation is already fresh', {\n ...logContext,\n isAlreadyFreshTranslation,\n currentRev: sourceDocument._rev,\n })\n\n if (!shouldOverwriteFreshTranslations && isAlreadyFreshTranslation) {\n devLog.info('Skipping fresh translation', logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'skipped', {\n targetId: translationMetadata.translations.find((t) => t._key === targetLanguage)?.value._ref,\n })\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n return\n }\n\n // Determine if we need to update an existing translation or create a new document\n const translationTarget = determineTranslationTarget({\n translationMetadata,\n targetLanguage,\n })\n const isNewTranslation = translationTarget.operation === 'create'\n\n devLog.debug('Translation target determined', {\n ...logContext,\n operation: translationTarget.operation,\n isNewTranslation,\n })\n\n let newDocument: SanityDocument | undefined\n\n // DIFFS TRANSLATION\n if (!isNewTranslation && shouldTranslateDiffs) {\n devLog.info('Starting diff-based translation', logContext)\n\n // Patch the changes that have been made to the source document into the translation target\n // This will result in the target document temporarily containing content in multiple languages\n const { currentTargetId, patch } = await patchTranslationTarget({\n client,\n currentSourceDocument: sourceDocument,\n sourceLanguage,\n translationMetadata,\n targetLanguage,\n })\n\n if (!currentTargetId) {\n devLog.warn('No target ID found for diff translation', logContext)\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n return\n }\n\n devLog.debug('Patching translation target', {\n ...logContext,\n currentTargetId,\n hasPatch: !!patch,\n })\n\n // Ask the Sanity agent to complete the translation of the target document\n newDocument = await translateDocumentInPlace({\n client,\n schemaId,\n dispatch,\n sourceDocument,\n languageFieldName,\n targetLanguage,\n targetId: currentTargetId,\n patch,\n })\n } else {\n // TRANSLATE ENTIRE DOCUMENT\n devLog.info('Starting full document translation', {\n ...logContext,\n translationTarget: translationTarget.operation,\n })\n\n newDocument = await translateEntireDocument({\n dispatch,\n client,\n schemaId,\n sourceDocument,\n targetLanguage,\n languageFieldName,\n translationTarget,\n translationPrompts,\n })\n }\n\n if (!newDocument) {\n devLog.error('Failed to create translation document', undefined, logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'error')\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n throw new Error('Failed to create translation document')\n }\n\n devLog.debug('Translation document created', {\n ...logContext,\n newDocumentId: newDocument._id,\n })\n\n // UPDATE TRANSLATION METADATA\n devLog.debug('Updating translation metadata', logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'updating_metadata', {\n targetId: newDocument._id,\n })\n\n await updateTranslationMetadata({\n client,\n sourceDocument,\n sourceLanguage,\n newDocument,\n targetLanguage,\n translationMetadata,\n isNewTranslation,\n })\n\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'completed')\n devLog.info('Translation completed successfully', {\n ...logContext,\n newDocumentId: newDocument._id,\n })\n\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n return newDocument._id\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n devLog.error('Translation failed', error instanceof Error ? error : new Error(String(error)), logContext)\n setJobStatus(dispatch, sourceDocument._id, targetLanguage, 'error', {\n errorMessage,\n })\n devLog.timeEnd('translateDocument')\n devLog.groupEnd()\n // Don't re-throw - let the batch continue with other translations\n return undefined\n }\n}\n\ninterface PatchTranslationTargetParams {\n client: SanityClient\n currentSourceDocument: SanityDocument\n sourceLanguage: string\n translationMetadata: TranslationMetadataDocument\n targetLanguage: string\n}\n\nconst patchTranslationTarget = async ({\n client,\n currentSourceDocument,\n translationMetadata,\n targetLanguage,\n}: PatchTranslationTargetParams) => {\n const sourceSnapshotString = translationMetadata.translationHistory.find(\n (h) => undraftId(h.sourceId) === undraftId(currentSourceDocument._id),\n )?.sourceSnapshot\n\n if (!sourceSnapshotString) {\n return {}\n }\n\n const sourceSnapshot = JSON.parse(sourceSnapshotString)\n const targetId = translationMetadata.translations.find((t) => t._key === targetLanguage)?.value._ref\n\n if (!targetId) {\n return {}\n }\n\n const currentTargetId = await client.fetch<string | null>(\n '*[_id in $ids] | order((_id match \"drafts*\") desc)[0]._id',\n { ids: [undraftId(targetId), draftId(targetId)] },\n )\n\n if (!currentTargetId) {\n console.log(`No document found for ${targetId}`)\n return {}\n }\n\n // create diff patch between the previously translated version of the source and the current version of the source\n const patch = diffPatch(sourceSnapshot, currentSourceDocument, {\n id: draftId(currentTargetId),\n })\n\n return { currentTargetId, patch }\n}\n","import type { Dispatch } from 'react'\nimport type { SanityClient } from 'sanity'\nimport type { TranslatableDocument, TranslationAction } from '../types'\nimport type { AssembleReferencesResult } from './assembleReferences'\nimport { devLog } from './devLog'\nimport { fetchTranslationPrompts } from './fetchTranslationPrompts'\nimport { localizeReferences } from './localizeReferences'\nimport { Semaphore } from './Semaphore'\nimport { setupTranslationJobStatuses } from './setupTranslationJobStatuses'\nimport { translateDocument } from './translateDocument'\n\ninterface TranslateDocumentsParams {\n sourceDocument: TranslatableDocument\n targetLanguages: Array<string>\n client: SanityClient\n dispatch: Dispatch<TranslationAction>\n languageFieldName: string\n shouldOverwriteFreshTranslations: boolean\n schemaId: string\n references: AssembleReferencesResult\n maxConcurrentTranslationJobs?: number\n maxReferenceDepth?: number\n shouldTranslateDiffs: boolean\n}\n\nconst translationSemaphore = new Semaphore(2)\n\nexport const translateDocumentSet = async ({\n client,\n sourceDocument,\n targetLanguages,\n dispatch,\n languageFieldName,\n shouldOverwriteFreshTranslations,\n schemaId,\n references = [],\n maxConcurrentTranslationJobs,\n shouldTranslateDiffs,\n}: TranslateDocumentsParams) => {\n const logContext = {\n documentId: sourceDocument._id,\n targetLanguages,\n referencesCount: references.length,\n maxConcurrentJobs: maxConcurrentTranslationJobs,\n shouldTranslateDiffs,\n shouldOverwriteFreshTranslations,\n }\n\n devLog.group('translateDocumentSet', logContext)\n devLog.time('translateDocumentSet')\n\n try {\n const sourceLanguage = sourceDocument[languageFieldName] as string\n\n if (!sourceLanguage) {\n devLog.error('Source language not found')\n throw new Error('Source language not found')\n }\n\n // If the config specifies a max concurrent translation jobs, update the semaphore\n if (maxConcurrentTranslationJobs) {\n devLog.debug('Updating translation semaphore permits', {\n ...logContext,\n newPermits: maxConcurrentTranslationJobs,\n })\n translationSemaphore.updatePermits(maxConcurrentTranslationJobs)\n }\n\n devLog.info('Starting document set translation', logContext)\n dispatch({\n type: 'SET_OVERALL_STATUS',\n payload: 'translating',\n })\n\n const sourceDocuments = [\n {\n _id: sourceDocument._id,\n _type: sourceDocument._type,\n // TODO: Handle this properly\n title: (sourceDocument.name || sourceDocument.title) as string | undefined,\n },\n ...references,\n ]\n\n const sourceDocumentIds = sourceDocuments.map((doc) => doc._id)\n const targetDocumentIds: Array<string> = []\n\n devLog.debug('Prepared document set for translation', {\n ...logContext,\n sourceDocumentIds: sourceDocumentIds.length,\n totalTranslationJobs: sourceDocumentIds.length * targetLanguages.length,\n })\n\n // Assemble prompts for translation task style guides\n const translationPrompts = await fetchTranslationPrompts({\n client,\n sourceLanguage,\n targetLanguages,\n sourceDocument,\n })\n\n devLog.info('Translation prompts', translationPrompts)\n\n // Dispatch new job statuses for each document\n setupTranslationJobStatuses(dispatch, sourceDocuments, targetLanguages)\n\n // Create translation tasks for all documents and all languages\n const translationTasks = sourceDocumentIds.flatMap((documentId) =>\n targetLanguages.map(async (targetLanguage) => {\n try {\n await translationSemaphore.withPermit(async () => {\n // Fetch the document\n const document = await client\n .withConfig({\n // This enables us to detect documents that might be stale due to unpublished changes\n perspective: 'raw',\n })\n .fetch<TranslatableDocument>('*[_id == $id][0]', {\n id: documentId,\n })\n if (document) {\n const targetDocumentId = await translateDocument({\n dispatch,\n client,\n sourceDocument: document,\n targetLanguage,\n languageFieldName,\n shouldOverwriteFreshTranslations,\n schemaId,\n shouldTranslateDiffs,\n translationPrompts,\n })\n\n if (targetDocumentId) {\n targetDocumentIds.push(targetDocumentId)\n }\n }\n })\n } catch (error) {\n // Log the error but don't fail the entire batch\n devLog.error(\n 'Individual translation task failed',\n error instanceof Error ? error : new Error(String(error)),\n {\n ...logContext,\n failedDocumentId: documentId,\n failedTargetLanguage: targetLanguage,\n },\n )\n // The error status should already be set by translateDocument\n }\n }),\n )\n\n // Use Promise.allSettled instead of Promise.all to wait for all tasks regardless of failures\n const results = await Promise.allSettled(translationTasks)\n\n // Log summary of results\n const succeeded = results.filter((r) => r.status === 'fulfilled').length\n const failed = results.filter((r) => r.status === 'rejected').length\n\n devLog.info('Translation tasks summary', {\n ...logContext,\n total: results.length,\n succeeded,\n failed,\n })\n\n devLog.info('All translation tasks completed', {\n ...logContext,\n targetDocumentIds: targetDocumentIds.length,\n })\n\n dispatch({\n type: 'SET_OVERALL_STATUS',\n payload: 'linking_references',\n })\n\n devLog.debug('Starting reference localization', {\n ...logContext,\n documentsToLocalize: targetDocumentIds.length,\n })\n\n await Promise.all(\n targetDocumentIds.map(async (documentId) => {\n await localizeReferences({\n client,\n documentId,\n languageFieldName,\n })\n }),\n )\n\n // Determine overall status based on individual job statuses\n const hasAnyFailures = failed > 0\n\n if (hasAnyFailures && succeeded === 0) {\n // All translations failed\n devLog.error('All translation tasks failed', undefined, logContext)\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'error' })\n } else if (hasAnyFailures) {\n // Partial success - some translations failed but others succeeded\n devLog.warn('Translation completed with some failures', {\n ...logContext,\n succeeded,\n failed,\n })\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'completed' })\n } else {\n // All translations succeeded\n devLog.info('Document set translation completed successfully', logContext)\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'completed' })\n }\n\n devLog.timeEnd('translateDocumentSet')\n devLog.groupEnd()\n } catch (error) {\n // This catch block should only catch unexpected errors that aren't handled above\n devLog.error(\n 'translateDocumentSet failed with unexpected error',\n error instanceof Error ? error : new Error(String(error)),\n logContext,\n )\n devLog.timeEnd('translateDocumentSet')\n devLog.groupEnd()\n dispatch({ type: 'SET_OVERALL_STATUS', payload: 'error' })\n throw error\n }\n}\n","import { Button, Flex } from '@sanity/ui'\nimport { useClient } from 'sanity'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { translateDocumentSet } from '../utils/translateDocumentSet'\n\ninterface ActionButtonBarProps {\n setIsDialogOpen: (isOpen: boolean) => void\n}\n\nexport const ActionButtonBar = ({ setIsDialogOpen }: ActionButtonBarProps) => {\n const {\n document,\n config,\n overallStatus,\n dispatch,\n references,\n selectedTargetLanguages,\n shouldOverwriteFreshTranslations,\n shouldTranslateDiffs,\n } = useTranslationContext()\n const client = useClient({ apiVersion: 'vX' })\n\n const handleTranslate = () => {\n translateDocumentSet({\n sourceDocument: document,\n targetLanguages: selectedTargetLanguages,\n client,\n dispatch,\n languageFieldName: config.languageFieldName,\n schemaId: config.schemaId,\n references,\n shouldOverwriteFreshTranslations,\n maxConcurrentTranslationJobs: config.maxConcurrentTranslationJobs,\n maxReferenceDepth: config.maxReferenceDepth,\n shouldTranslateDiffs,\n })\n }\n\n const handleSelectAll = () => {\n dispatch({\n type: 'SET_SELECTED_TARGET_LANGUAGES',\n payload: config.supportedLanguages.map((lang) => lang.id).filter((id) => id !== document.language),\n })\n }\n\n const handleSelectNone = () => {\n dispatch({\n type: 'SET_SELECTED_TARGET_LANGUAGES',\n payload: [],\n })\n }\n\n return (\n <Flex justify=\"space-between\" gap={2}>\n <Flex justify=\"flex-start\" gap={2}>\n <Button mode=\"ghost\" size={2} onClick={handleSelectAll}>\n Select All\n </Button>\n <Button mode=\"ghost\" size={2} onClick={handleSelectNone}>\n Select None\n </Button>\n </Flex>\n <Flex justify=\"flex-end\" gap={2}>\n <Button onClick={() => setIsDialogOpen(false)} mode=\"ghost\" size={2}>\n Cancel\n </Button>\n <Button\n mode=\"ghost\"\n tone=\"positive\"\n size={2}\n onClick={handleTranslate}\n disabled={selectedTargetLanguages.length === 0 || !['idle', 'completed'].includes(overallStatus)}\n >\n Translate\n </Button>\n </Flex>\n </Flex>\n )\n}\n","import { Badge, Button, Checkbox, Flex, Inline, Spinner, Text } from '@sanity/ui'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport type { PluginConfig } from '../types'\n\ninterface LanguageCheckboxProps {\n lang: PluginConfig['supportedLanguages'][number]\n isLoading: boolean\n}\n\nexport const LanguageCheckbox = ({ lang, isLoading }: LanguageCheckboxProps) => {\n const { document, dispatch, selectedTargetLanguages, translationMetadata } = useTranslationContext()\n const isDisabled = lang.id === document.language\n const isChecked = selectedTargetLanguages.includes(lang.id)\n const hasTranslation = translationMetadata?.translations?.some((translation) => translation._key === lang.id)\n const isStale =\n hasTranslation &&\n translationMetadata?.translationHistory?.some(\n (history) => history.language === lang.id && history.sourceRev !== document._rev,\n )\n\n const handleChange = () => {\n if (isDisabled) return\n\n const updatedLanguages = isChecked\n ? selectedTargetLanguages.filter((langId) => langId !== lang.id)\n : [...selectedTargetLanguages, lang.id]\n\n dispatch({\n type: 'SET_SELECTED_TARGET_LANGUAGES',\n payload: updatedLanguages,\n })\n }\n\n if (isLoading) {\n return (\n <Button type=\"button\" mode=\"bleed\" size={2} onClick={handleChange} disabled muted>\n <Flex align=\"center\" justify=\"center\" paddingY={3}>\n <Spinner size={1} />\n </Flex>\n </Button>\n )\n }\n\n return (\n <Button\n type=\"button\"\n mode={isChecked ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleChange}\n disabled={isDisabled}\n tone={isChecked ? 'primary' : 'default'}\n muted\n >\n <Flex align=\"center\" gap={2} style={{ cursor: 'pointer' }}>\n <Inline space={3}>\n <Checkbox checked={isChecked} onChange={handleChange} label={lang.title} disabled={isDisabled} />\n <Flex direction=\"column\" gap={3}>\n <Text>{lang.title}</Text>\n {!isDisabled ? (\n <Text size={1} muted>\n {hasTranslation && !isDisabled ? 'Already translated' : 'Not translated'}\n </Text>\n ) : (\n <Text size={1} muted>\n The current language\n </Text>\n )}\n </Flex>\n </Inline>\n {!isDisabled && hasTranslation && (\n <Flex flex={1} justify=\"flex-end\">\n <Badge tone={isStale ? 'caution' : 'positive'} size={3} muted>\n {isStale ? 'Stale' : 'Fresh'}\n </Badge>\n </Flex>\n )}\n </Flex>\n </Button>\n )\n}\n","import { Card, Grid } from '@sanity/ui'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { useTranslationMetadata } from '../hooks/useTranslationMetadata'\nimport { LanguageCheckbox } from './LanguageCheckbox'\n\nexport const LanguageSelectionPanel = () => {\n // Get the configuration from the context\n const { document, config } = useTranslationContext()\n\n const { loading } = useTranslationMetadata({\n documentId: document._id,\n })\n\n return (\n <Card padding={4} muted border>\n <Grid columns={[1, 2]} gap={3}>\n {config?.supportedLanguages.map((lang) => (\n <LanguageCheckbox key={lang.id} lang={lang} isLoading={loading} />\n ))}\n </Grid>\n </Card>\n )\n}\n","import type { SanityClient, SanityDocument } from 'sanity'\nimport type { TranslatableDocument } from '../types'\nimport { findKeyValues, type RecursiveSearchable } from './findKeyValues/findKeyValues'\n\ninterface AssembleReferencesParams {\n client: SanityClient\n sourceDocument: SanityDocument\n maxReferenceDepth: number\n translatableSchemaTypes?: Array<string>\n}\n\nexport type AssembleReferencesResult = Array<{\n _id: SanityDocument['_id']\n _type: SanityDocument['_type']\n title?: string\n}>\n\n// Sanity documents are objects of arbitrary shape, which can\n// contain references to other documents. References are always\n// represented as a `_ref` key with a value of the referenced document's\n// `_id`. This function takes a Sanity document, appends all `_ref` keys\n// within it to an array, then fetches the references documents and repeats\n// the process until the maximum reference depth is reached.\n\nexport const assembleReferences = async ({\n client,\n sourceDocument,\n maxReferenceDepth,\n translatableSchemaTypes = [],\n}: AssembleReferencesParams): Promise<AssembleReferencesResult> => {\n // Input validation\n if (!client) {\n throw new Error('assembleReferences: client is required')\n }\n\n if (!sourceDocument || !sourceDocument._id) {\n throw new Error('assembleReferences: sourceDocument with _id is required')\n }\n\n if (typeof maxReferenceDepth !== 'number' || maxReferenceDepth < 0) {\n throw new Error('assembleReferences: maxReferenceDepth must be a non-negative number')\n }\n\n const references = new Set<string>()\n const documentCache = new Map<string, TranslatableDocument | null>()\n const errors: Array<{ refId: string; error: Error }> = []\n\n let currentDepthDocuments = [sourceDocument]\n\n for (let depth = 0; depth < maxReferenceDepth && currentDepthDocuments.length > 0; depth++) {\n // Collect all reference IDs from current depth documents\n const allRefIds = new Set<string>()\n\n for (const document of currentDepthDocuments) {\n try {\n const refResults = findKeyValues<string>(document as RecursiveSearchable, '_ref')\n for (const result of refResults) {\n const refId = result.value\n if (typeof refId === 'string' && refId.length > 0 && !references.has(refId) && !documentCache.has(refId)) {\n allRefIds.add(refId)\n }\n }\n } catch (error) {\n console.error('assembleReferences: Error finding references in document:', error)\n }\n }\n\n if (allRefIds.size === 0) {\n break\n }\n\n // Batch fetch all references for this depth level\n const refIdArray = Array.from(allRefIds)\n try {\n const batchResults = await client.fetch<TranslatableDocument[]>('*[_id in $ids]', { ids: refIdArray })\n\n // Create a map of fetched documents by ID\n const fetchedDocuments = new Map<string, TranslatableDocument>()\n for (const doc of batchResults) {\n fetchedDocuments.set(doc._id, doc)\n }\n\n // Process each reference ID\n const nextDepthDocuments: TranslatableDocument[] = []\n\n for (const refId of refIdArray) {\n const fetchedDoc = fetchedDocuments.get(refId)\n\n if (fetchedDoc) {\n // Skip non-translatable documents\n if (translatableSchemaTypes.length > 0 && !translatableSchemaTypes.includes(fetchedDoc._type)) {\n documentCache.set(refId, null)\n continue\n }\n\n documentCache.set(refId, fetchedDoc)\n references.add(refId)\n nextDepthDocuments.push(fetchedDoc)\n } else {\n // Document not found\n documentCache.set(refId, null)\n console.warn(`assembleReferences: Document with _id \"${refId}\" not found`)\n }\n }\n\n currentDepthDocuments = nextDepthDocuments\n } catch (fetchError) {\n // Log the error but continue processing\n const error = fetchError instanceof Error ? fetchError : new Error(String(fetchError))\n errors.push({ refId: `batch(${refIdArray.join(',')})`, error })\n console.error('assembleReferences: Failed to batch fetch documents:', error.message)\n break\n }\n }\n\n // Log summary of errors if any occurred\n if (errors.length > 0) {\n console.warn(`assembleReferences: Encountered ${errors.length} error(s) while fetching references`)\n }\n\n // Convert the cached documents to the expected result format\n const result: AssembleReferencesResult = []\n for (const refId of references) {\n const cachedDoc = documentCache.get(refId)\n if (cachedDoc) {\n result.push({\n _id: cachedDoc._id,\n _type: cachedDoc._type,\n title: (cachedDoc.name || cachedDoc.title) as string | undefined,\n })\n }\n }\n\n return result\n}\n","import { Button, Checkbox, Flex, Inline, Select, Stack, Text } from '@sanity/ui'\nimport { useEffect, useState } from 'react'\nimport { useClient } from 'sanity'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { assembleReferences } from '../utils/assembleReferences'\n\nexport const ReferenceConfigPanel = () => {\n const { dispatch, document, shouldTranslateReferences, maxReferenceDepth, config, references } =\n useTranslationContext()\n const client = useClient({ apiVersion: 'vX' })\n const [isLoadingReferences, setIsLoadingReferences] = useState(false)\n const maxDepth = config.maxReferenceDepth || 3\n\n useEffect(() => {\n const updateReferences = async () => {\n setIsLoadingReferences(true)\n\n if (!shouldTranslateReferences) {\n dispatch({\n type: 'SET_REFERENCES',\n payload: [],\n })\n return\n }\n\n const newReferences = await assembleReferences({\n client,\n sourceDocument: document,\n maxReferenceDepth,\n translatableSchemaTypes: config.translatableSchemaTypes,\n })\n dispatch({\n type: 'SET_REFERENCES',\n payload: newReferences,\n })\n\n setIsLoadingReferences(false)\n }\n\n updateReferences()\n }, [document, client, dispatch, shouldTranslateReferences, maxReferenceDepth, config.translatableSchemaTypes])\n\n const handleMaxReferenceDepthChange = async (event: React.ChangeEvent<HTMLSelectElement>) => {\n dispatch({\n type: 'SET_MAX_REFERENCE_DEPTH',\n payload: Number.parseInt(event.target.value),\n })\n }\n\n const handleShouldTranslateChange = () => {\n dispatch({\n type: 'SET_SHOULD_TRANSLATE_REFERENCES',\n payload: !shouldTranslateReferences,\n })\n }\n\n return (\n <Stack space={2}>\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n type=\"button\"\n mode={shouldTranslateReferences ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleShouldTranslateChange}\n tone={shouldTranslateReferences ? 'primary' : 'neutral'}\n >\n <Inline space={2}>\n <Checkbox\n checked={shouldTranslateReferences}\n onChange={handleShouldTranslateChange}\n label={shouldTranslateReferences ? 'Disable' : 'Enable'}\n />\n <Text>Translate References</Text>\n </Inline>\n </Button>\n {shouldTranslateReferences ? (\n <Inline space={2}>\n <Text>Max Depth:</Text>\n <Select\n disabled={!shouldTranslateReferences}\n placeholder=\"Depth\"\n onChange={handleMaxReferenceDepthChange}\n value={maxReferenceDepth.toString()}\n >\n {Array.from({ length: maxDepth }, (_, i) => i + 1).map((depth) => (\n <option key={depth} value={depth.toString()}>\n {depth}\n </option>\n ))}\n </Select>\n </Inline>\n ) : null}\n </Flex>\n {shouldTranslateReferences ? (\n <Flex padding={2} justify=\"flex-end\">\n <Text size={1} muted>\n {isLoadingReferences\n ? 'Loading references...'\n : references.length === 0\n ? 'No translatable references found.'\n : `${references.length} translatable references found.`}\n </Text>\n </Flex>\n ) : null}\n </Stack>\n )\n}\n","import { Badge, Button, Checkbox, Flex, Inline, Stack, Text } from '@sanity/ui'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport { ReferenceConfigPanel } from './ReferenceConfigPanel'\n\nexport const WriteSettingsPanel = () => {\n const { dispatch, shouldOverwriteFreshTranslations, shouldTranslateDiffs } = useTranslationContext()\n\n const handleShouldOverwriteFreshTranslationsChange = () => {\n dispatch({\n type: 'SET_SHOULD_OVERWRITE_FRESH_TRANSLATIONS',\n payload: !shouldOverwriteFreshTranslations,\n })\n }\n\n const handleShouldTranslateDiffsChange = () => {\n dispatch({\n type: 'SET_SHOULD_TRANSLATE_DIFFS',\n payload: !shouldTranslateDiffs,\n })\n }\n\n return (\n <Stack space={2}>\n <ReferenceConfigPanel />\n {/* Overwrite fresh translations */}\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n type=\"button\"\n mode={shouldOverwriteFreshTranslations ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleShouldOverwriteFreshTranslationsChange}\n tone={shouldOverwriteFreshTranslations ? 'primary' : 'neutral'}\n >\n <Inline space={2}>\n <Checkbox\n checked={shouldOverwriteFreshTranslations}\n onChange={handleShouldOverwriteFreshTranslationsChange}\n label={shouldOverwriteFreshTranslations ? 'Disable' : 'Enable'}\n />\n <Stack space={2}>\n <Text>Overwrite Fresh Translations</Text>\n <Text size={1} muted>\n All existing translations will be overwritten even if they are fresh.\n </Text>\n </Stack>\n </Inline>\n </Button>\n </Flex>\n\n {/* Translate diffs */}\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n type=\"button\"\n mode={shouldTranslateDiffs ? 'ghost' : 'bleed'}\n size={2}\n onClick={handleShouldTranslateDiffsChange}\n tone={shouldTranslateDiffs ? 'primary' : 'neutral'}\n >\n <Inline space={2}>\n <Checkbox\n checked={shouldTranslateDiffs}\n onChange={handleShouldOverwriteFreshTranslationsChange}\n label={shouldTranslateDiffs ? 'Disable' : 'Enable'}\n />\n <Stack space={3}>\n <Inline space={1}>\n <Text>Translate Diffs</Text>\n <Badge tone=\"caution\">Experimental</Badge>\n </Inline>\n <Text size={1} muted>\n Only re-translate content that has changed in the source document.\n </Text>\n </Stack>\n </Inline>\n </Button>\n </Flex>\n </Stack>\n )\n}\n","import { Card, Label, Stack } from '@sanity/ui'\nimport type { FC } from 'react'\nimport { ActionButtonBar } from './ActionButtonBar'\nimport { LanguageSelectionPanel } from './LanguageSelectionPanel'\nimport { WriteSettingsPanel } from './WriteSettingsPanel'\n\ninterface TranslationConfigViewProps {\n setIsDialogOpen: (isOpen: boolean) => void\n}\n\nexport const TranslationConfigView: FC<TranslationConfigViewProps> = ({ setIsDialogOpen }) => {\n return (\n <Stack space={4}>\n <Stack space={2}>\n <Label>Languages</Label>\n <LanguageSelectionPanel />\n </Stack>\n\n <Stack space={2}>\n <Label>Settings</Label>\n <Card padding={4} border muted>\n <WriteSettingsPanel />\n </Card>\n </Stack>\n <ActionButtonBar setIsDialogOpen={setIsDialogOpen} />\n </Stack>\n )\n}\n","import { ArrowRightIcon, CheckmarkIcon, CircleIcon, ErrorOutlineIcon, PanelRightIcon } from '@sanity/icons'\nimport { Badge, Box, Button, Card, Code, Flex, Heading, Inline, Label, Spinner, Stack, Text, Tooltip } from '@sanity/ui'\nimport { useMemo } from 'react'\nimport { useOpenInNewPane } from 'sanity-plugin-utils'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\n\nconst TERMINAL_STATUSES = ['completed', 'skipped', 'error']\n\nexport const TranslationStatusPanel = () => {\n const { overallStatus, translationJobs } = useTranslationContext()\n\n const headline = useMemo(\n () => (overallStatus === 'completed' ? 'Translation completed' : 'Translation in progress'),\n [overallStatus],\n )\n\n const jobs = useMemo(() => Array.from(translationJobs.values()), [translationJobs])\n\n return (\n <Stack space={4}>\n <Heading size={2}>{headline}</Heading>\n <ProgressBar progress={jobs.filter((job) => TERMINAL_STATUSES.includes(job.status)).length} max={jobs.length} />\n <Stack space={3}>\n <Label>Translations</Label>\n <Card padding={2} tone=\"transparent\">\n <Stack space={2}>\n <ul style={{ listStyleType: 'none', paddingInlineStart: '0' }}>\n {jobs.map((job) => (\n <li key={job._id}>\n <Box padding={3}>\n <Flex justify=\"space-between\" align=\"center\">\n <Inline space={2}>\n <Flex align=\"center\" justify=\"center\" style={{ width: '24px', height: '24px' }}>\n {['completed', 'skipped'].includes(job.status) ? (\n <CheckmarkIcon fontSize={24} />\n ) : job.status === 'error' ? (\n <Box style={{ color: 'var(--card-critical-fg-color)' }}>\n <ErrorOutlineIcon fontSize={24} />\n </Box>\n ) : job.status === 'queued' ? (\n <CircleIcon fontSize={24} />\n ) : (\n <Spinner />\n )}\n </Flex>\n <Stack space={3}>\n <Inline space={2}>\n <Text size={1} weight=\"semibold\">\n {job.title || 'Untitled Document'}\n </Text>\n <ArrowRightIcon fontSize={18} />\n <Code size={1}>{job.language}</Code>\n </Inline>\n <Code size={1}>\n {job._type} — {job._id.slice(-6)}\n </Code>\n {job.status === 'error' && job.errorMessage ? (\n <Card tone=\"critical\" padding={2} radius={2}>\n <Text size={1}>Error: {job.errorMessage}</Text>\n </Card>\n ) : null}\n </Stack>\n </Inline>\n <Flex gap={2} align=\"center\">\n {job.status === 'skipped' ? <SkippedBadge /> : null}\n {job.status === 'error' ? <ErrorBadge /> : null}\n {job.targetId ? (\n <TranslationOpenerButton\n target={{\n _id: job.targetId,\n _type: job._type as string,\n }}\n />\n ) : null}\n </Flex>\n </Flex>\n </Box>\n </li>\n ))}\n </ul>\n </Stack>\n </Card>\n </Stack>\n </Stack>\n )\n}\n\nconst ProgressBar = ({ progress, max = 100 }: { progress: number; max?: number }) => {\n const percentage = Math.min((progress / max) * 100, 100)\n\n return (\n <Stack space={2}>\n <div\n style={{\n width: '100%',\n height: '8px',\n backgroundColor: 'var(--card-border-color)',\n borderRadius: '4px',\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n width: `${percentage}%`,\n height: '100%',\n backgroundColor: 'var(--card-accent-fg-color)',\n borderRadius: '4px',\n transition: 'width 0.3s ease-in-out',\n }}\n />\n </div>\n <Flex justify=\"space-between\" align=\"center\">\n <Text size={1} muted>\n {percentage.toFixed(0)}%\n </Text>\n <Text size={1} muted>\n {progress} / {max} jobs completed.\n </Text>\n </Flex>\n </Stack>\n )\n}\n\nconst TranslationOpenerButton = ({ target }: { target: { _id: string; _type: string } }) => {\n const openInNewPane = useOpenInNewPane(target._id, target._type)\n\n return <Button mode=\"bleed\" text=\"View\" iconRight={PanelRightIcon} onClick={() => openInNewPane()} />\n}\n\nconst SkippedBadge = () => (\n <Tooltip\n portal\n content={\n <Box padding={1}>\n <Text size={1} muted>\n There was already a fresh translation for this document and language.\n </Text>\n </Box>\n }\n >\n <Badge tone=\"neutral\">Skipped</Badge>\n </Tooltip>\n)\n\nconst ErrorBadge = () => (\n <Tooltip\n portal\n content={\n <Box padding={1}>\n <Text size={1} muted>\n This translation failed. Check the error message for details.\n </Text>\n </Box>\n }\n >\n <Badge tone=\"critical\">Failed</Badge>\n </Tooltip>\n)\n","import type { FC } from 'react'\nimport { useTranslationContext } from '../hooks/useTranslationContext'\nimport type { OverallTranslationStatus } from '../types'\nimport { devLog } from '../utils/devLog'\nimport { TranslationConfigView } from './TranslationConfigPanel'\nimport { TranslationStatusPanel } from './TranslationStatusPanel'\n\ninterface TranslationDialogProps {\n setIsDialogOpen: (isOpen: boolean) => void\n}\n\nconst STATES_IN_WHICH_TO_SHOW_CONFIG: Array<OverallTranslationStatus> = ['fetching_metadata', 'idle']\n\nconst STATES_IN_WHICH_TO_SHOW_TRANSLATION_PROGRESS: Array<OverallTranslationStatus> = [\n 'translating',\n 'linking_references',\n 'completed',\n]\n\nconst STATES_IN_WHICH_TO_SHOW_ERROR: Array<OverallTranslationStatus> = ['error']\n\nconst _STATES_IN_WHICH_TO_SHOW_COMPLETE: Array<OverallTranslationStatus> = ['completed']\n\nexport const TranslationDialog: FC<TranslationDialogProps> = ({ setIsDialogOpen }) => {\n const { overallStatus, document } = useTranslationContext()\n\n devLog.debug('TranslationDialog rendered', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n\n if (STATES_IN_WHICH_TO_SHOW_CONFIG.includes(overallStatus)) {\n devLog.debug('Showing translation config view', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n return <TranslationConfigView setIsDialogOpen={setIsDialogOpen} />\n }\n\n if (STATES_IN_WHICH_TO_SHOW_TRANSLATION_PROGRESS.includes(overallStatus)) {\n devLog.debug('Showing translation progress panel', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n return <TranslationStatusPanel />\n }\n\n if (STATES_IN_WHICH_TO_SHOW_ERROR.includes(overallStatus)) {\n devLog.warn('Translation error state reached', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n return <div>Error occurred</div>\n }\n\n // if (STATES_IN_WHICH_TO_SHOW_COMPLETE.includes(overallStatus)) {\n // \treturn <div>Translation completed</div>;\n // }\n\n devLog.warn('Unhandled translation dialog state', {\n documentId: document._id,\n overallStatus,\n component: 'TranslationDialog',\n })\n\n return <div>Unhandled overall state</div>\n}\n","import { TranslateIcon } from '@sanity/icons'\nimport { useState } from 'react'\nimport type { DocumentActionDescription, DocumentActionProps } from 'sanity'\nimport { TranslationDialog } from './components/TranslationDialog'\nimport { TranslationContextProvider } from './hooks/useTranslationContext/TranslationContextProvider'\nimport type { PluginConfig, TranslatableDocument } from './types'\nimport { devLog } from './utils/devLog'\n\ninterface TranslateActionProps extends DocumentActionProps {\n config: PluginConfig\n}\n\nexport const getTranslateAction = (config: PluginConfig) => {\n return ({ draft, published }: TranslateActionProps): DocumentActionDescription | null => {\n const document = draft ?? published\n const [isDialogOpen, setIsDialogOpen] = useState(false)\n\n devLog.debug('TranslateAction initialized', {\n documentId: document?._id,\n documentType: document?._type,\n })\n\n if (!document || !config.translatableSchemaTypes?.includes(document._type)) {\n devLog.warn('Document not in translatable schema types', {\n documentType: document?._type,\n translatableTypes: config.translatableSchemaTypes,\n })\n return null\n }\n\n if (!config) {\n devLog.error('Missing config in TranslateAction')\n return null\n }\n\n return {\n label: 'Translate',\n icon: TranslateIcon,\n onHandle: () => {\n devLog.info('Translation dialog opened', {\n documentId: document._id,\n documentType: document._type,\n component: 'TranslateAction',\n })\n setIsDialogOpen(true)\n },\n dialog: isDialogOpen && {\n type: 'dialog',\n onClose: () => setIsDialogOpen(false),\n header: 'Translate Document',\n content: (\n <TranslationContextProvider document={document as TranslatableDocument} config={config}>\n <TranslationDialog setIsDialogOpen={setIsDialogOpen} />\n </TranslationContextProvider>\n ),\n },\n }\n }\n}\n","import { definePlugin } from 'sanity'\nimport { getGiveTranslationFeedbackAction } from './GiveTranslationFeedbackAction'\nimport { translationGlossaryTerm } from './schemas/translationGlossaryTerm.schema'\nimport { translationHistory } from './schemas/translationHistory.schema'\nimport { translationSettings } from './schemas/translationSettings.schema'\nimport { getTranslateAction } from './TranslateAction'\nimport type { PluginConfig } from './types'\n\n/**\n * AI translation plugin for Sanity Studio\n * See the PluginConfig export for configuration options\n *\n * @public\n */\nexport const aiTranslationPlugin = definePlugin<PluginConfig>((config) => {\n return {\n name: 'sanity-plugin-ai-translation',\n document: {\n actions: [getTranslateAction(config), getGiveTranslationFeedbackAction(config)],\n },\n schema: {\n types: [translationSettings, translationGlossaryTerm],\n },\n }\n})\n\n/**\n * Schema for translation history\n *\n * @public\n */\nexport const translationHistorySchema = translationHistory\n"],"names":["translationHistory","translationSettings","result"],"mappings":"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"}