sanity-plugin-internationalized-array
5.3.35.3.4
dist/index.js.map~
dist/index.js.mapModified+1−1
Index: package/dist/index.js.map
===================================================================
--- package/dist/index.js.map
+++ package/dist/index.js.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"index.js","names":["{apiVersion: internationalizedArray.apiVersion}","apiVersion","getSelectedValue(internationalizedArray.select, deferredDocument)","select","useMemo(\n () => getSelectedValue(internationalizedArray.select, deferredDocument),\n [internationalizedArray.select, deferredDocument],\n )","useMemo(() => {\n // Use workspace name if available, otherwise create a stable hash\n if (workspace?.name) {\n return workspace.name\n }\n // Create a stable hash from workspace properties that matter for caching\n const workspaceKey = {\n name: workspace?.name,\n title: workspace?.title,\n // Add other stable properties as needed\n }\n return JSON.stringify(workspaceKey)\n }, [workspace])","JSON.stringify(workspaceKey)","workspace?.name","workspace?.title","createCacheKey(selectedValue, workspaceId)","useMemo(\n () => createCacheKey(selectedValue, workspaceId),\n [selectedValue, workspaceId],\n )","useMemo(() => {\n if (Array.isArray(internationalizedArray.languages)) {\n return null // Return null for synchronous arrays\n }\n\n // Create or get cached promise for React.use\n return createOrGetPromise(async () => {\n if (typeof internationalizedArray.languages === 'function') {\n const result = await internationalizedArray.languages(client, selectedValue)\n // Populate function cache for use outside React context\n setFunctionCache(internationalizedArray.languages, selectedValue, result, workspaceId)\n return result\n }\n return internationalizedArray.languages\n }, cacheKey)\n }, [internationalizedArray, client, selectedValue, workspaceId, cacheKey])","async () => {\n if (typeof internationalizedArray.languages === 'function') {\n const result = await internationalizedArray.languages(client, selectedValue)\n // Populate function cache for use outside React context\n setFunctionCache(internationalizedArray.languages, selectedValue, result, workspaceId)\n return result\n }\n return internationalizedArray.languages\n }","internationalizedArray.languages","createOrGetPromise(async () => {\n if (typeof internationalizedArray.languages === 'function') {\n const result = await internationalizedArray.languages(client, selectedValue)\n // Populate function cache for use outside React context\n setFunctionCache(internationalizedArray.languages, selectedValue, result, workspaceId)\n return result\n }\n return internationalizedArray.languages\n }, cacheKey)","languageFilterOptions.documentTypes.includes(documentType)","documentTypes","languageFilterEnabled\n ? languages.filter((language) => selectedLanguageIds.includes(language.id))\n : languages","useMemo(() => {\n const languageFilterEnabled = languageFilterOptions.documentTypes.includes(documentType)\n\n return languageFilterEnabled\n ? languages.filter((language) => selectedLanguageIds.includes(language.id))\n : languages\n }, [documentType, languageFilterOptions, languages, selectedLanguageIds])","{...internationalizedArray, languages, filteredLanguages}","useMemo(\n () => ({...internationalizedArray, languages, filteredLanguages}),\n [filteredLanguages, internationalizedArray, languages],\n )","<InternationalizedArrayContext.Provider value={context}>\n {props.children}\n </InternationalizedArrayContext.Provider>","children","InternationalizedArrayContext.Provider","_c","languages.map((language) => {\n const languageTitle: string = getLanguageDisplay(\n languageDisplay,\n language.title,\n language.id,\n )\n return (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n data-testid={`add-${language.id}`}\n disabled={readOnly || languagesInUse.includes(language.id)}\n text={languageTitle}\n // Only show plus icon if there's one row or less AND only showing codes\n icon={\n languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === 'codeOnly'\n ? undefined\n : AddIcon\n }\n value={language.id}\n onClick={() => handleClick(language.id)}\n />\n )\n })","languages.length","(language) => {\n const languageTitle: string = getLanguageDisplay(\n languageDisplay,\n language.title,\n language.id,\n )\n return (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n data-testid={`add-${language.id}`}\n disabled={readOnly || languagesInUse.includes(language.id)}\n text={languageTitle}\n // Only show plus icon if there's one row or less AND only showing codes\n icon={\n languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === 'codeOnly'\n ? undefined\n : AddIcon\n }\n value={language.id}\n onClick={() => handleClick(language.id)}\n />\n )\n }","length","<Grid\n gridTemplateColumns={Math.min(languages.length, MAX_COLUMNS[languageDisplay])}\n gap={2}\n data-testid=\"add-buttons-grid\"\n >\n {languages.map((language) => {\n const languageTitle: string = getLanguageDisplay(\n languageDisplay,\n language.title,\n language.id,\n )\n return (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n data-testid={`add-${language.id}`}\n disabled={readOnly || languagesInUse.includes(language.id)}\n text={languageTitle}\n // Only show plus icon if there's one row or less AND only showing codes\n icon={\n languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === 'codeOnly'\n ? undefined\n : AddIcon\n }\n value={language.id}\n onClick={() => handleClick(language.id)}\n />\n )\n })}\n </Grid>","Math.min(languages.length, MAX_COLUMNS[languageDisplay])","_c","(typeName: string): unknown => {\n if (!typeName) return undefined\n\n // Extract the base type name from internationalized array type\n // e.g., \"internationalizedArrayBodyValue\" -> \"body\"\n const match = typeName.match(/^internationalizedArray(.+)Value$/)\n if (!match || !match[1]) return undefined\n\n const baseTypeName = match[1].charAt(0).toLowerCase() + match[1].slice(1)\n\n // Check if it's a known array-based type (Portable Text fields)\n const arrayBasedTypes = new Set(['body', 'htmlContent', 'blockContent', 'portableText'])\n if (arrayBasedTypes.has(baseTypeName)) {\n return []\n }\n\n // Try to look up the schema type to determine if it's an array\n const schemaType = schema.get(typeName)\n if (schemaType && 'fields' in schemaType) {\n // Check if this is an object type with a 'value' field\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const fields = schemaType.fields as Array<{\n name: string\n type?: {jsonType?: string; name?: string; type?: string; of?: unknown}\n }>\n const valueField = fields.find((f) => f.name === 'value')\n if (valueField) {\n const fieldType = valueField.type\n // Check if the value field is an array type\n if (\n fieldType?.jsonType === 'array' ||\n fieldType?.name === 'array' ||\n fieldType?.type === 'array' ||\n fieldType?.of !== undefined ||\n (fieldType?.name && arrayBasedTypes.has(fieldType.name))\n ) {\n return []\n }\n }\n }\n\n return undefined\n }","(f) => f.name === 'value'","useCallback(\n (typeName: string): unknown => {\n if (!typeName) return undefined\n\n // Extract the base type name from internationalized array type\n // e.g., \"internationalizedArrayBodyValue\" -> \"body\"\n const match = typeName.match(/^internationalizedArray(.+)Value$/)\n if (!match || !match[1]) return undefined\n\n const baseTypeName = match[1].charAt(0).toLowerCase() + match[1].slice(1)\n\n // Check if it's a known array-based type (Portable Text fields)\n const arrayBasedTypes = new Set(['body', 'htmlContent', 'blockContent', 'portableText'])\n if (arrayBasedTypes.has(baseTypeName)) {\n return []\n }\n\n // Try to look up the schema type to determine if it's an array\n const schemaType = schema.get(typeName)\n if (schemaType && 'fields' in schemaType) {\n // Check if this is an object type with a 'value' field\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const fields = schemaType.fields as Array<{\n name: string\n type?: {jsonType?: string; name?: string; type?: string; of?: unknown}\n }>\n const valueField = fields.find((f) => f.name === 'value')\n if (valueField) {\n const fieldType = valueField.type\n // Check if the value field is an array type\n if (\n fieldType?.jsonType === 'array' ||\n fieldType?.name === 'array' ||\n fieldType?.type === 'array' ||\n fieldType?.of !== undefined ||\n (fieldType?.name && arrayBasedTypes.has(fieldType.name))\n ) {\n return []\n }\n }\n }\n\n return undefined\n },\n [schema],\n )","async (languageId: string) => {\n const value = getFormValue([])\n if (!isSanityDocument(value)) {\n toast.push({\n status: 'error',\n title: 'No document value found',\n })\n return\n }\n const documentsToTranslation = getDocumentsToTranslate(value, [])\n\n const alreadyTranslated = documentsToTranslation.filter(\n (translation) => translation?.[LANGUAGE_FIELD_NAME] === languageId,\n )\n const removeDuplicates = documentsToTranslation.reduce<DocumentsToTranslate[]>(\n (filteredTranslations, translation) => {\n if (\n alreadyTranslated.filter(\n (alreadyTranslation) => alreadyTranslation.pathString === translation.pathString,\n ).length > 0\n ) {\n return filteredTranslations\n }\n const translationAlreadyExists = filteredTranslations.filter(\n (filteredTranslation) => filteredTranslation.path === translation.path,\n )\n\n if (translationAlreadyExists.length > 0) {\n return filteredTranslations\n }\n filteredTranslations.push(translation)\n return filteredTranslations\n },\n [],\n )\n if (removeDuplicates.length === 0) {\n const language = filteredLanguages.find((l) => l.id === languageId)\n toast.push({\n status: 'warning',\n title: `No missing translations for ${language?.title || languageId} found.`,\n })\n return\n }\n\n // Build patches for each field missing the selected language\n const patches: (FormSetIfMissingPatch | FormInsertPatch)[] = []\n\n for (const toTranslate of removeDuplicates) {\n const path = toTranslate.path\n\n const initialValue = getInitialValueForType(toTranslate._type)\n\n const ifMissing = setIfMissing([], path)\n const insertValue = insert(\n [\n {\n _key: randomKey(),\n [LANGUAGE_FIELD_NAME]: languageId,\n _type: toTranslate._type,\n value: initialValue,\n },\n ],\n 'after',\n [...path, -1],\n )\n patches.push(ifMissing)\n patches.push(insertValue)\n }\n\n onChange(PatchEvent.from(patches.flat()))\n }","translation","useCallback(\n async (languageId: string) => {\n const value = getFormValue([])\n if (!isSanityDocument(value)) {\n toast.push({\n status: 'error',\n title: 'No document value found',\n })\n return\n }\n const documentsToTranslation = getDocumentsToTranslate(value, [])\n\n const alreadyTranslated = documentsToTranslation.filter(\n (translation) => translation?.[LANGUAGE_FIELD_NAME] === languageId,\n )\n const removeDuplicates = documentsToTranslation.reduce<DocumentsToTranslate[]>(\n (filteredTranslations, translation) => {\n if (\n alreadyTranslated.filter(\n (alreadyTranslation) => alreadyTranslation.pathString === translation.pathString,\n ).length > 0\n ) {\n return filteredTranslations\n }\n const translationAlreadyExists = filteredTranslations.filter(\n (filteredTranslation) => filteredTranslation.path === translation.path,\n )\n\n if (translationAlreadyExists.length > 0) {\n return filteredTranslations\n }\n filteredTranslations.push(translation)\n return filteredTranslations\n },\n [],\n )\n if (removeDuplicates.length === 0) {\n const language = filteredLanguages.find((l) => l.id === languageId)\n toast.push({\n status: 'warning',\n title: `No missing translations for ${language?.title || languageId} found.`,\n })\n return\n }\n\n // Build patches for each field missing the selected language\n const patches: (FormSetIfMissingPatch | FormInsertPatch)[] = []\n\n for (const toTranslate of removeDuplicates) {\n const path = toTranslate.path\n\n const initialValue = getInitialValueForType(toTranslate._type)\n\n const ifMissing = setIfMissing([], path)\n const insertValue = insert(\n [\n {\n _key: randomKey(),\n [LANGUAGE_FIELD_NAME]: languageId,\n _type: toTranslate._type,\n value: initialValue,\n },\n ],\n 'after',\n [...path, -1],\n )\n patches.push(ifMissing)\n patches.push(insertValue)\n }\n\n onChange(PatchEvent.from(patches.flat()))\n },\n [getInitialValueForType, onChange, toast, getFormValue, filteredLanguages],\n )","<Box>\n <Text size={1} weight=\"semibold\">\n Add translation to internationalized fields\n </Text>\n </Box>","[]","<Stack gap={3} data-testid=\"document-add-buttons\">\n <Box>\n <Text size={1} weight=\"semibold\">\n Add translation to internationalized fields\n </Text>\n </Box>\n <AddButtons\n readOnly={Boolean(formState?.readOnly)}\n handleClick={handleDocumentButtonClick}\n languagesInUse={[]}\n />\n </Stack>","Boolean(formState?.readOnly)","_c","_temp","<DocumentAddButtons />","props.renderDefault(props)","props.renderDefault","<Stack gap={5}>\n <DocumentAddButtons />\n {props.renderDefault(props)}\n </Stack>","_c","props.renderDefault(props)","props.renderDefault","<InternationalizedArrayProvider\n internationalizedArray={props.pluginConfig}\n documentType={props.documentType}\n >\n {props.renderDefault(props)}\n </InternationalizedArrayProvider>","documentType","pluginConfig","props.pluginConfig","props.documentType","_c","{apiVersion: props.apiVersion}","apiVersion","_c","{portal: true, placement: 'bottom-end'}","<Button\n mode=\"bleed\"\n tone=\"default\"\n fontSize={1}\n padding={2}\n icon={TranslateIcon}\n aria-label=\"Add translation\"\n title=\"Add translation\"\n data-testid=\"add-translation-menu\"\n disabled={readOnly}\n />","languages.map((language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n ))","(language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n )","buttonAddAll ? (\n <>\n <MenuDivider />\n <MenuItem\n text={addAllTitle}\n icon={TranslateIcon}\n disabled={readOnly || allFilteredLanguagesArePresent}\n data-testid=\"field-menu-add-all\"\n onClick={onAddAll}\n />\n </>\n ) : null","<Menu>\n {languages.map((language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n ))}\n {buttonAddAll ? (\n <>\n <MenuDivider />\n <MenuItem\n text={addAllTitle}\n icon={TranslateIcon}\n disabled={readOnly || allFilteredLanguagesArePresent}\n data-testid=\"field-menu-add-all\"\n onClick={onAddAll}\n />\n </>\n ) : null}\n </Menu>","<Flex justify=\"flex-end\" data-testid=\"field-menu\">\n <MenuButton\n id={menuId}\n popover={{portal: true, placement: 'bottom-end'}}\n button={\n <Button\n mode=\"bleed\"\n tone=\"default\"\n fontSize={1}\n padding={2}\n icon={TranslateIcon}\n aria-label=\"Add translation\"\n title=\"Add translation\"\n data-testid=\"add-translation-menu\"\n disabled={readOnly}\n />\n }\n menu={\n <Menu>\n {languages.map((language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n ))}\n {buttonAddAll ? (\n <>\n <MenuDivider />\n <MenuItem\n text={addAllTitle}\n icon={TranslateIcon}\n disabled={readOnly || allFilteredLanguagesArePresent}\n data-testid=\"field-menu-add-all\"\n onClick={onAddAll}\n />\n </>\n ) : null}\n </Menu>\n }\n />\n </Flex>","_c","_Fragment","<code>internationalizedArray</code>","<code>id</code>","<Text>\n An array of language objects must be passed into the <code>internationalizedArray</code>{' '}\n helper function, each with an <code>id</code> and <code>title</code> field. Example:\n </Text>","<Card tone=\"caution\" border radius={2} padding={3}>\n <Stack gap={4}>\n <Text>\n An array of language objects must be passed into the <code>internationalizedArray</code>{' '}\n helper function, each with an <code>id</code> and <code>title</code> field. Example:\n </Text>\n <Card padding={2} border radius={2}>\n <Code size={1} language=\"javascript\">\n {JSON.stringify(schemaExample, null, 2)}\n </Code>\n </Card>\n </Stack>\n </Card>","_c","{\n itemsNeedingMigration,\n}: MigrationBannerProps","<Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>","<Text size={1} weight=\"semibold\">\n Data migration required\n </Text>","<Text size={1} muted>\n {itemsNeedingMigration.length} item\n {itemsNeedingMigration.length === 1 ? '' : 's'}{' '}\n {itemsNeedingMigration.length === 1 ? 'needs' : 'need'} to be migrated to the v5 format.\n </Text>","length","itemsNeedingMigration.length === 1 ? '' : 's'","itemsNeedingMigration.length === 1 ? 'needs' : 'need'","<code>_key</code>","<code>language</code>","<Box marginTop={2}>\n <Text size={1}>\n This field still uses the v4 format where language is stored in <code>_key</code>.\n Migrate to the v5 format where language is stored in <code>language</code>.{' '}\n <a\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n href=\"https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/README.md#migrate-from-v4-to-v5\"\n >\n Learn more\n </a>\n .\n </Text>\n </Box>","<Card tone=\"caution\" padding={3} radius={2} border>\n <Flex gap={3} align=\"center\">\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack gap={2} flex={1}>\n <Text size={1} weight=\"semibold\">\n Data migration required\n </Text>\n <Text size={1} muted>\n {itemsNeedingMigration.length} item\n {itemsNeedingMigration.length === 1 ? '' : 's'}{' '}\n {itemsNeedingMigration.length === 1 ? 'needs' : 'need'} to be migrated to the v5 format.\n </Text>\n <Box marginTop={2}>\n <Text size={1}>\n This field still uses the v4 format where language is stored in <code>_key</code>.\n Migrate to the v5 format where language is stored in <code>language</code>.{' '}\n <a\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n href=\"https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/README.md#migrate-from-v4-to-v5\"\n >\n Learn more\n </a>\n .\n </Text>\n </Box>\n </Stack>\n </Flex>\n </Card>","_c","value?.filter((v) => !v[LANGUAGE_FIELD_NAME]) ?? []","(v) => !v[LANGUAGE_FIELD_NAME]","value?.filter","['_type']","typeof documentType === 'string' && languageFilterOptions.documentTypes.includes(documentType)","languageFilterOptions.documentTypes","typeof documentType === 'string' && builtInLanguageFilter.documentTypes.includes(documentType)","builtInLanguageFilter.documentTypes","usingLanguageFilterPlugin || usingBuiltInLanguageFilter\n ? members.filter((member) => {\n // This member is the outer object created by the plugin\n // Satisfy TS\n if (member.kind !== 'item') {\n return false\n }\n\n // This is the inner \"value\" field member created by this plugin\n const valueMember = member.item.members[0]\n\n // Satisfy TS\n if (!valueMember || valueMember.kind !== 'field') {\n return false\n }\n // The built-in filter receives the full languages list so it can\n // surface fields with invalid language IDs rather than hiding them.\n // The language filter plugin does not support this.\n return usingBuiltInLanguageFilter\n ? internationalizedArrayLanguageFilter(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n languages,\n )\n : languageFilterOptions.filterField(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n )\n })\n : members","useMemo(\n () =>\n usingLanguageFilterPlugin || usingBuiltInLanguageFilter\n ? members.filter((member) => {\n // This member is the outer object created by the plugin\n // Satisfy TS\n if (member.kind !== 'item') {\n return false\n }\n\n // This is the inner \"value\" field member created by this plugin\n const valueMember = member.item.members[0]\n\n // Satisfy TS\n if (!valueMember || valueMember.kind !== 'field') {\n return false\n }\n // The built-in filter receives the full languages list so it can\n // surface fields with invalid language IDs rather than hiding them.\n // The language filter plugin does not support this.\n return usingBuiltInLanguageFilter\n ? internationalizedArrayLanguageFilter(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n languages,\n )\n : languageFilterOptions.filterField(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n )\n })\n : members,\n [\n usingLanguageFilterPlugin,\n usingBuiltInLanguageFilter,\n members,\n selectedLanguageIds,\n languages,\n languageFilterOptions,\n ],\n )","(addLanguageKeys: string[] | string) => {\n if (readOnly) {\n return\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n const formValue = getFormValue(props.path) as InternationalizedArrayItem[]\n if (!filteredLanguages?.length) {\n return\n }\n\n const patches = createAddLanguagePatches({\n addLanguageKeys: Array.isArray(addLanguageKeys) ? addLanguageKeys : [addLanguageKeys],\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value: formValue,\n })\n\n onChange([setIfMissing([]), ...patches])\n }","filteredLanguages?.length","path","schemaType.name","useCallback(\n (addLanguageKeys: string[] | string) => {\n if (readOnly) {\n return\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n const formValue = getFormValue(props.path) as InternationalizedArrayItem[]\n if (!filteredLanguages?.length) {\n return\n }\n\n const patches = createAddLanguagePatches({\n addLanguageKeys: Array.isArray(addLanguageKeys) ? addLanguageKeys : [addLanguageKeys],\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value: formValue,\n })\n\n onChange([setIfMissing([]), ...patches])\n },\n [filteredLanguages, languages, onChange, schemaType, getFormValue, props.path, readOnly],\n )","['_rev']","isPristineDocument(useContext(EventsContext))","useContext(EventsContext)","value\n ?.map((v) => v[LANGUAGE_FIELD_NAME] ?? v._key)\n .filter(Boolean)\n .join(',')","(v) => v[LANGUAGE_FIELD_NAME] ?? v._key","value\n ?.map","useMemo(() => {\n const languageKeys = languageKeysFromValue?.split(',') || []\n if (!languageKeys?.length) return []\n if (!languages?.length) return []\n\n return languages.filter((l) => languageKeys?.find((key) => key === l.id)).map((l) => l.id)\n }, [languageKeysFromValue, languages])","languageKeysFromValue?.split","languages?.length","[]","(l) => l.id","() => {\n const hasAddedDefaultLanguages = defaultLanguages\n .filter((language) => languages.find((l) => l.id === language))\n .every((language) => addedLanguages.includes(language))\n\n if (\n (isPristine || documentExists) &&\n !isDeleting &&\n !isDeleted &&\n !hasAddedDefaultLanguages &&\n !shouldMigrateArray &&\n !readOnly\n ) {\n const languagesToAdd = defaultLanguages\n .filter((language) => !addedLanguages.includes(language))\n .filter((language) => languages.find((l) => l.id === language))\n // Account for strict mode by scheduling the update.\n const timeout = setTimeout(() => {\n if (!readOnly) handleAddLanguages(languagesToAdd)\n })\n return () => clearTimeout(timeout)\n }\n return undefined\n }","[\n isPristine,\n documentExists,\n isDeleted,\n isDeleting,\n handleAddLanguages,\n defaultLanguages,\n addedLanguages,\n languages,\n readOnly,\n shouldMigrateArray,\n ]","l","language","() => {\n if (readOnly || !value?.length || !languages?.length) {\n return\n }\n\n // Create a new value array in the correct order\n // This would also strip out values that don't have a language as the key\n const updatedValue = value\n .reduce((acc, v) => {\n const newIndex = languages.findIndex((l) => l.id === v?.[LANGUAGE_FIELD_NAME])\n\n if (newIndex > -1) {\n acc[newIndex] = v\n }\n\n return acc\n }, [] as InternationalizedArrayItem[])\n .filter(Boolean)\n\n if (value?.length !== updatedValue.length) {\n toast.push({\n title: 'There was an error reordering languages',\n status: 'warning',\n })\n }\n\n onChange(set(updatedValue))\n }","value?.length","v","useCallback(() => {\n if (readOnly || !value?.length || !languages?.length) {\n return\n }\n\n // Create a new value array in the correct order\n // This would also strip out values that don't have a language as the key\n const updatedValue = value\n .reduce((acc, v) => {\n const newIndex = languages.findIndex((l) => l.id === v?.[LANGUAGE_FIELD_NAME])\n\n if (newIndex > -1) {\n acc[newIndex] = v\n }\n\n return acc\n }, [] as InternationalizedArrayItem[])\n .filter(Boolean)\n\n if (value?.length !== updatedValue.length) {\n toast.push({\n title: 'There was an error reordering languages',\n status: 'warning',\n })\n }\n\n onChange(set(updatedValue))\n }, [toast, languages, onChange, value, readOnly])","useMemo(() => {\n if (!value?.length || !languages?.length) {\n return true\n }\n\n return value?.every((v) => languages.find((l) => l?.id === v?.[LANGUAGE_FIELD_NAME]))\n }, [value, languages])","value?.every((v) => languages.find((l) => l?.id === v?.[LANGUAGE_FIELD_NAME]))","value?.every","useMemo(() => {\n if (!value?.length || !addedLanguages.length) {\n return []\n }\n\n return value\n .map((v, vIndex) =>\n vIndex === addedLanguages.findIndex((language) => language === v[LANGUAGE_FIELD_NAME])\n ? null\n : v,\n )\n .filter(Boolean)\n }, [value, addedLanguages])","value\n .map((v, vIndex) =>\n vIndex === addedLanguages.findIndex((language) => language === v[LANGUAGE_FIELD_NAME])\n ? null\n : v,\n )\n .filter(Boolean)","(v, vIndex) =>\n vIndex === addedLanguages.findIndex((language) => language === v[LANGUAGE_FIELD_NAME])\n ? null\n : v","(item) => item.id && item.title","() => {\n if (restoreOrder && languagesOutOfOrder.length > 0 && allKeysAreLanguages && !readOnly) {\n handleRestoreOrder()\n }\n }","[restoreOrder, languagesOutOfOrder, allKeysAreLanguages, handleRestoreOrder, readOnly]","languagesOutOfOrder.length","filteredLanguages.every((language) => addedLanguages.includes(language.id))","(language) => addedLanguages.includes(language.id)","useMemo(\n () => filteredLanguages.every((language) => addedLanguages.includes(language.id)),\n [filteredLanguages, addedLanguages],\n )","() => {\n handleAddLanguages(filteredLanguages.map((language) => language.id))\n }","(language) => language.id","useCallback(() => {\n handleAddLanguages(filteredLanguages.map((language) => language.id))\n }, [filteredLanguages, handleAddLanguages])","<Feedback />","canAddLanguages && buttonLocations.includes('fieldMenu')","canAddLanguages && buttonLocations.includes('field') && !allFilteredLanguagesArePresent","createAddAllTitle(value, filteredLanguages)","showFieldButtons ? (\n <Stack gap={2}>\n <AddButtons\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n />\n {buttonAddAll ? (\n <Button\n tone=\"primary\"\n mode=\"ghost\"\n data-testid=\"add-all-languages\"\n disabled={readOnly || allFilteredLanguagesArePresent}\n icon={AddIcon}\n text={addAllTitle}\n onClick={addAllMissingLanguages}\n />\n ) : null}\n </Stack>\n ) : null","showFieldMenu ? (\n <CompactAddButton\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n onAddAll={addAllMissingLanguages}\n buttonAddAll={buttonAddAll}\n addAllTitle={addAllTitle}\n allFilteredLanguagesArePresent={allFilteredLanguagesArePresent}\n />\n ) : null","filteredMembers.map((member) => {\n if (member.kind === 'item') {\n return <ArrayOfObjectsItem {...props} key={member.key} member={member} />\n }\n return <MemberItemError key={member.key} member={member} />\n })","(member) => {\n if (member.kind === 'item') {\n return <ArrayOfObjectsItem {...props} key={member.key} member={member} />\n }\n return <MemberItemError key={member.key} member={member} />\n }","member","<MigrationBanner itemsNeedingMigration={itemsNeedingMigration} />","!showFieldMenu && !showFieldButtons && !fieldHasMembers ? (\n <Card border tone=\"transparent\" padding={3} radius={2}>\n <Text size={1}>This internationalized field currently has no translations.</Text>\n </Card>\n ) : null","<Stack gap={2}>\n {showFieldMenu ? (\n <CompactAddButton\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n onAddAll={addAllMissingLanguages}\n buttonAddAll={buttonAddAll}\n addAllTitle={addAllTitle}\n allFilteredLanguagesArePresent={allFilteredLanguagesArePresent}\n />\n ) : null}\n {filteredMembers.map((member) => {\n if (member.kind === 'item') {\n return <ArrayOfObjectsItem {...props} key={member.key} member={member} />\n }\n return <MemberItemError key={member.key} member={member} />\n })}\n <MigrationBanner itemsNeedingMigration={itemsNeedingMigration} />\n\n {/* Give some feedback in the UI so the field doesn't look \"missing\" */}\n {!showFieldMenu && !showFieldButtons && !fieldHasMembers ? (\n <Card border tone=\"transparent\" padding={3} radius={2}>\n <Text size={1}>This internationalized field currently has no translations.</Text>\n </Card>\n ) : null}\n\n {fieldButtons}\n </Stack>","_c","_temp","_temp2","_temp3","_temp4","path.slice(0, -1)","parentValue?.map((v) => v[LANGUAGE_FIELD_NAME]) ?? []","(v) => v[LANGUAGE_FIELD_NAME]","parentValue?.map","useMemo(\n () => parentValue?.map((v) => v[LANGUAGE_FIELD_NAME]) ?? [],\n [parentValue],\n )","(event: React.MouseEvent<HTMLButtonElement>): void => {\n const languageId = event?.currentTarget?.value\n\n if (!value || !languages?.length || !languages.find((l) => l.id === languageId)) {\n return\n }\n\n onChange([set(languageId, [LANGUAGE_FIELD_NAME])])\n }","languages?.length","<Button fontSize={1} text={`Change \"${value[LANGUAGE_FIELD_NAME]}\"`} />","`Change \"${value[LANGUAGE_FIELD_NAME]}\"`","languages.map((lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n ))","(lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n )","<Menu>\n {languages.map((lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n ))}\n </Menu>","{portal: true}","<MenuButton\n button={<Button fontSize={1} text={`Change \"${value[LANGUAGE_FIELD_NAME]}\"`} />}\n id={`${value[LANGUAGE_FIELD_NAME]}-change-key`}\n menu={\n <Menu>\n {languages.map((lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n ))}\n </Menu>\n }\n popover={{portal: true}}\n />","`${value[LANGUAGE_FIELD_NAME]}-change-key`","{\n isDefault,\n readOnly,\n onChange,\n}: {\n isDefault: boolean\n readOnly: boolean\n onChange: (patch: FormPatch[] | PatchEvent | FormPatch) => void\n}","(): void => {\n onChange(unset())\n }","<Text muted size={1}>\n Can't remove default language\n </Text>","['right', 'left']","{paddingBottom: '2px'}","<span style={{paddingBottom: '2px'}}>\n <Button\n mode=\"bleed\"\n icon={RemoveCircleIcon}\n tone=\"critical\"\n disabled={readOnly || isDefault}\n onClick={handleUnset}\n />\n </span>","readOnly || isDefault","<Tooltip\n animate\n disabled={!isDefault}\n content={\n <Text muted size={1}>\n Can't remove default language\n </Text>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <span style={{paddingBottom: '2px'}}>\n <Button\n mode=\"bleed\"\n icon={RemoveCircleIcon}\n tone=\"critical\"\n disabled={readOnly || isDefault}\n onClick={handleUnset}\n />\n </span>\n </Tooltip>","!isDefault","(patches: unknown) => {\n // Ensure patches is an array before proceeding with paste logic\n // For single patch operations (like unset), pass through directly\n if (!Array.isArray(patches)) {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n }\n\n // Check if this is a paste operation into an empty or uninitialized Portable Text field\n const valueField = props.value?.value\n const isEmptyOrUndefined =\n valueField === undefined ||\n valueField === null ||\n (Array.isArray(valueField) && valueField.length === 0)\n\n if (isEmptyOrUndefined) {\n // Check for insert patches that are trying to operate on a non-existent structure\n const hasProblematicInsert = patches.some((patch: {type?: string; path?: unknown[]}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return false\n }\n\n // Look for insert patches targeting the value field or direct array index\n if (\n patch.type === 'insert' &&\n patch.path &&\n Array.isArray(patch.path) &&\n patch.path.length > 0\n ) {\n // The path might be ['value', index] or just [index] depending on context\n const isTargetingValue = patch.path[0] === 'value' || typeof patch.path[0] === 'number'\n return isTargetingValue\n }\n return false\n })\n\n if (hasProblematicInsert) {\n // First, ensure the value field exists as an empty array if it doesn't\n const initPatch =\n valueField === undefined ? {type: 'setIfMissing', path: ['value'], value: []} : null\n\n // Transform the patches to ensure they work with the nested structure\n const fixedPatches = patches.map(\n (patch: {type?: string; path?: unknown[]; [key: string]: unknown}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return patch\n }\n\n if (patch.type === 'insert' && patch.path && Array.isArray(patch.path)) {\n // Ensure the path is correct for the nested structure\n const fixedPath = patch.path[0] === 'value' ? patch.path : ['value', ...patch.path]\n const fixedPatch = {...patch, path: fixedPath}\n return fixedPatch\n }\n return patch\n },\n )\n\n // If we need to initialize the field, include that patch first\n const allPatches = initPatch ? [initPatch, ...fixedPatches] : fixedPatches\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(allPatches as Parameters<typeof originalOnChange>[0])\n }\n }\n\n // For all other cases, pass through unchanged\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n }","value","(patch: {type?: string; path?: unknown[]}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return false\n }\n\n // Look for insert patches targeting the value field or direct array index\n if (\n patch.type === 'insert' &&\n patch.path &&\n Array.isArray(patch.path) &&\n patch.path.length > 0\n ) {\n // The path might be ['value', index] or just [index] depending on context\n const isTargetingValue = patch.path[0] === 'value' || typeof patch.path[0] === 'number'\n return isTargetingValue\n }\n return false\n }","(patch: {type?: string; path?: unknown[]; [key: string]: unknown}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return patch\n }\n\n if (patch.type === 'insert' && patch.path && Array.isArray(patch.path)) {\n // Ensure the path is correct for the nested structure\n const fixedPath = patch.path[0] === 'value' ? patch.path : ['value', ...patch.path]\n const fixedPatch = {...patch, path: fixedPath}\n return fixedPatch\n }\n return patch\n }","useCallback(\n (patches: unknown) => {\n // Ensure patches is an array before proceeding with paste logic\n // For single patch operations (like unset), pass through directly\n if (!Array.isArray(patches)) {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n }\n\n // Check if this is a paste operation into an empty or uninitialized Portable Text field\n const valueField = props.value?.value\n const isEmptyOrUndefined =\n valueField === undefined ||\n valueField === null ||\n (Array.isArray(valueField) && valueField.length === 0)\n\n if (isEmptyOrUndefined) {\n // Check for insert patches that are trying to operate on a non-existent structure\n const hasProblematicInsert = patches.some((patch: {type?: string; path?: unknown[]}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return false\n }\n\n // Look for insert patches targeting the value field or direct array index\n if (\n patch.type === 'insert' &&\n patch.path &&\n Array.isArray(patch.path) &&\n patch.path.length > 0\n ) {\n // The path might be ['value', index] or just [index] depending on context\n const isTargetingValue = patch.path[0] === 'value' || typeof patch.path[0] === 'number'\n return isTargetingValue\n }\n return false\n })\n\n if (hasProblematicInsert) {\n // First, ensure the value field exists as an empty array if it doesn't\n const initPatch =\n valueField === undefined ? {type: 'setIfMissing', path: ['value'], value: []} : null\n\n // Transform the patches to ensure they work with the nested structure\n const fixedPatches = patches.map(\n (patch: {type?: string; path?: unknown[]; [key: string]: unknown}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return patch\n }\n\n if (patch.type === 'insert' && patch.path && Array.isArray(patch.path)) {\n // Ensure the path is correct for the nested structure\n const fixedPath = patch.path[0] === 'value' ? patch.path : ['value', ...patch.path]\n const fixedPatch = {...patch, path: fixedPath}\n return fixedPatch\n }\n return patch\n },\n )\n\n // If we need to initialize the field, include that patch first\n const allPatches = initPatch ? [initPatch, ...fixedPatches] : fixedPatches\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(allPatches as Parameters<typeof originalOnChange>[0])\n }\n }\n\n // For all other cases, pass through unchanged\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n },\n [originalOnChange, props.value?.value],\n )","languages?.length\n ? Boolean(languages.find((l) => l.id === props.value[LANGUAGE_FIELD_NAME]))\n : false","keyIsValid && language ? getLanguageDisplay(languageDisplay, language.title, language.id) : ''","languages?.find","l","props.inputProps.members\n .filter((m) => m.kind === 'field' && m.name === 'value')\n .map((member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n })","members","path","(member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n }","(m) => m.kind === 'field' && m.name === 'value'","{\n ...props.inputProps,\n members: props.inputProps.members\n .filter((m) => m.kind === 'field' && m.name === 'value')\n .map((member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n }),\n value: props.value,\n // Use our wrapped onChange handler\n onChange: wrappedOnChange,\n }","inputProps","props.inputProps","useMemo(\n () => ({\n ...props.inputProps,\n members: props.inputProps.members\n .filter((m) => m.kind === 'field' && m.name === 'value')\n .map((member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n }),\n value: props.value,\n // Use our wrapped onChange handler\n onChange: wrappedOnChange,\n }),\n [\n props.inputProps,\n props.value,\n wrappedOnChange,\n languageTitle,\n keyIsValid,\n originalOnChange,\n props.path,\n ],\n )","<Spinner />","defaultLanguages.includes(value[LANGUAGE_FIELD_NAME])","getToneFromValidation(validation)","props.inputProps.renderInput(inlineProps)","<Box flex={1}>{props.inputProps.renderInput(inlineProps)}</Box>","<RemoveButton\n isDefault={isDefault}\n readOnly={Boolean(readOnly)}\n onChange={originalOnChange}\n />","Boolean(readOnly)","<Flex align=\"flex-end\" gap={2}>\n <Box flex={1}>{props.inputProps.renderInput(inlineProps)}</Box>\n <RemoveButton\n isDefault={isDefault}\n readOnly={Boolean(readOnly)}\n onChange={originalOnChange}\n />\n </Flex>","<Card paddingTop={2} tone={getToneFromValidation(validation)}>\n <Flex align=\"flex-end\" gap={2}>\n <Box flex={1}>{props.inputProps.renderInput(inlineProps)}</Box>\n <RemoveButton\n isDefault={isDefault}\n readOnly={Boolean(readOnly)}\n onChange={originalOnChange}\n />\n </Flex>\n </Card>","patch","_c","_Fragment","array","object","\"language\"","\"_key\""],"sources":["../src/cache.ts","../src/constants.ts","../src/utils/getDocumentsToTranslate.ts","../src/utils/getLanguageDisplay.ts","../src/components/getSelectedValue.ts","../src/components/InternationalizedArrayContext.tsx","../src/components/AddButtons.tsx","../src/components/DocumentAddButtons.tsx","../src/components/InternationalizedArrayFormInput.tsx","../src/utils/hasInternationalizedArrayField.ts","../src/components/InternationalizedArrayLayout.tsx","../src/components/Preload.tsx","../src/utils/checkAllLanguagesArePresent.ts","../src/utils/createAddAllTitle.ts","../src/types.ts","../src/utils/createAddLanguagePatches.ts","../src/fieldActions/index.ts","../src/components/createFieldName.ts","../src/utils/internationalizedArrayLanguageFilter.ts","../src/components/CompactAddButton.tsx","../src/components/Feedback.tsx","../src/components/MigrationBanner.tsx","../src/components/InternationalizedArray.tsx","../src/utils/getLanguagesFieldOption.ts","../src/schema/array.ts","../src/components/getToneFromValidation.ts","../src/components/InternationalizedInput.tsx","../src/schema/object.ts","../src/plugin.tsx"],"sourcesContent":["import type {Language, LanguageCallback} from './types'\n\nconst namespace = 'sanity-plugin-internationalized-array'\n\nconst version = 'v1'\n\n// Cache for function keys to avoid recalculating them\nconst functionKeyCache = new WeakMap<LanguageCallback, string>()\n\n// Cache for React.use promises\nconst promiseCache = new Map<string, Promise<Language[]>>()\n\n// Cache for function references to enable sharing between same functions\nconst functionCache = new Map<string, Language[]>()\n\n// Helper to create a cache key string from an array\nfunction stringifyCacheKey(key: unknown[]): string {\n return JSON.stringify(key)\n}\n\n// Enhanced preload function that can use custom cache keys\nexport const preloadWithKey = (fn: () => Promise<Language[]>, key: (string | number)[]) => {\n const keyStr = stringifyCacheKey(key)\n if (!promiseCache.has(keyStr)) {\n promiseCache.set(keyStr, fn())\n }\n}\n\n// Cache busting: clear all promise caches\nexport const clear = () => {\n promiseCache.clear()\n}\n\n// Peeking into entries outside of suspense\nexport const peek = (selectedValue: Record<string, unknown>) => {\n const key = stringifyCacheKey([version, namespace, selectedValue])\n const promise = promiseCache.get(key)\n if (promise) {\n // Check if promise is resolved\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const status = (promise as any)._status\n if (status === 'fulfilled') {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return (promise as any)._value as Language[] | undefined\n }\n }\n return undefined\n}\n\n// Helper function to create a stable cache key that matches the component's key structure\nexport const createCacheKey = (selectedValue: Record<string, unknown>, workspaceId?: string) => {\n const selectedValueHash = JSON.stringify(selectedValue)\n return workspaceId\n ? [version, namespace, selectedValueHash, workspaceId]\n : [version, namespace, selectedValueHash]\n}\n\n// Create or get cached promise for React.use\nexport const createOrGetPromise = (\n fn: () => Promise<Language[]>,\n key: (string | number | Record<string, unknown>)[],\n): Promise<Language[]> => {\n const keyStr = stringifyCacheKey(key)\n if (promiseCache.has(keyStr)) {\n return promiseCache.get(keyStr)!\n }\n const promise = fn()\n promiseCache.set(keyStr, promise)\n return promise\n}\n\n// Generate a unique key for a function reference (cached for performance)\nconst getFunctionKey = (fn: LanguageCallback): string => {\n // Check if we already have a cached key for this function\n const cachedKey = functionKeyCache.get(fn)\n if (cachedKey) {\n return cachedKey\n }\n\n // Create a hash for functions (only when needed)\n const fnStr = fn.toString()\n let hash = 0\n // Only hash the first 100 characters for performance\n const maxLength = Math.min(fnStr.length, 100)\n for (let i = 0; i < maxLength; i++) {\n const char = fnStr.charCodeAt(i)\n hash = (hash << 5) - hash + char\n hash &= hash // Convert to 32-bit integer\n }\n const key = `anonymous_${Math.abs(hash)}`\n functionKeyCache.set(fn, key)\n return key\n}\n\n// Create a cache key that includes function identity\nconst createFunctionCacheKey = (\n fn: LanguageCallback,\n selectedValue: Record<string, unknown>,\n workspaceId?: string,\n): string => {\n const functionKey = getFunctionKey(fn)\n const selectedValueHash = JSON.stringify(selectedValue)\n return workspaceId\n ? `${functionKey}:${selectedValueHash}:${workspaceId}`\n : `${functionKey}:${selectedValueHash}`\n}\n\n// Function-aware cache operations\nexport const getFunctionCache = (\n fn: LanguageCallback,\n selectedValue: Record<string, unknown>,\n workspaceId?: string,\n): Language[] | undefined => {\n const key = createFunctionCacheKey(fn, selectedValue, workspaceId)\n return functionCache.get(key)\n}\n\nexport const setFunctionCache = (\n fn: LanguageCallback,\n selectedValue: Record<string, unknown>,\n languages: Language[],\n workspaceId?: string,\n): void => {\n const key = createFunctionCacheKey(fn, selectedValue, workspaceId)\n functionCache.set(key, languages)\n}\n","import type {PluginConfig} from './types'\n\n/**\n * The field name used to identify the language of an internationalized array item.\n *\n * In v4.x this was '_key', in v5+ this is 'language'.\n * ```ts\n * {\n * \"description\": [\n * {\n * \"_key\": \"kjjNvZHK8Y2QpTEf3K5jc\",\n * \"_type\": \"internationalizedArrayTextValue\",\n * \"language\": \"en\"\n * \"value\": \"This is the description in English\"\n * },\n * {\n * \"_key\": \"kjjNvZHK8Y2QpTEf3K5jc\",\n * \"_type\": \"internationalizedArrayTextValue\",\n * \"language\": \"es\"\n * \"value\": \"This is the description in Spanish\"\n * },\n * ]\n * }\n * ```\n */\nexport const LANGUAGE_FIELD_NAME = 'language' as const\n\nexport const MAX_COLUMNS = {\n codeOnly: 5,\n titleOnly: 4,\n titleAndCode: 3,\n}\n\nexport const CONFIG_DEFAULT: Required<PluginConfig> = {\n languages: [],\n select: {},\n defaultLanguages: [],\n fieldTypes: [],\n apiVersion: '2025-10-15',\n buttonLocations: ['field'],\n buttonAddAll: true,\n restoreOrder: true,\n languageDisplay: 'codeOnly',\n includeForDocumentType: (documentType) => documentType !== 'translation.metadata',\n languageFilter: {\n documentTypes: [],\n },\n}\n","import type {SanityDocument} from 'sanity'\n\nexport interface DocumentsToTranslate {\n path: (string | number)[]\n pathString: string\n _key: string\n /** Language identifier (e.g., 'en', 'fr'). Added in v5. */\n language: string\n _type: string\n [key: string]: unknown\n}\n\n/**\n * Recursively traverses a Sanity document (or any nested value) and collects\n * all internationalized array items found within it.\n *\n * An item is considered an internationalized array value when its `_type`\n * starts with `\"internationalizedArray\"` and ends with `\"Value\"`.\n *\n * The function walks through objects and arrays, skipping keys that start\n * with `_` (internal Sanity fields like `_id`, `_type`, `_rev`). Each\n * returned item includes the original properties plus `path` (array of\n * segments) and `pathString` (dot-joined) indicating where it was found.\n */\nexport const getDocumentsToTranslate = (\n // oxlint-disable-next-line typescript-eslint/no-redundant-type-constituents\n value: SanityDocument | unknown,\n rootPath: (string | number)[] = [],\n): DocumentsToTranslate[] => {\n if (Array.isArray(value)) {\n const arrayRootPath = [...rootPath]\n\n // if item contains internationalized return array\n const internationalizedValues = value.filter((item) => {\n if (Array.isArray(item)) return false\n\n if (typeof item === 'object') {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const type = item?._type as string | undefined\n return type?.startsWith('internationalizedArray') && type?.endsWith('Value')\n }\n return false\n })\n\n if (internationalizedValues.length > 0) {\n return internationalizedValues.map((internationalizedValue) => {\n return Object.assign({}, internationalizedValue, {\n path: arrayRootPath,\n pathString: arrayRootPath.join('.'),\n })\n })\n }\n\n if (value.length > 0) {\n return value.flatMap((item, index) =>\n getDocumentsToTranslate(item, [...arrayRootPath, index]),\n )\n }\n\n return []\n }\n if (typeof value === 'object' && value) {\n const startsWithUnderscoreRegex = /^_/\n const itemKeys = Object.keys(value).filter(\n (key) => !key.match(startsWithUnderscoreRegex),\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n ) as (keyof typeof value)[]\n\n return itemKeys.flatMap((item) => {\n const selectedValue = value[item] as unknown\n const path = [...rootPath, item]\n return getDocumentsToTranslate(selectedValue, path)\n })\n }\n return []\n}\n","import type {LanguageDisplay} from '../types'\n\n/**\n * Formats a language label for display in buttons and field headers\n * based on the configured `languageDisplay` mode:\n *\n * - `'codeOnly'` -> uppercase code, e.g. `\"EN\"`\n * - `'titleOnly'` -> title as-is, e.g. `\"English\"`\n * - `'titleAndCode'` -> title with uppercase code, e.g. `\"English (EN)\"`\n *\n * Falls back to `title` for any unrecognized display mode.\n */\nexport function getLanguageDisplay(\n languageDisplay: LanguageDisplay,\n title: string,\n code: string,\n): string {\n if (languageDisplay === 'codeOnly') return code.toUpperCase()\n if (languageDisplay === 'titleOnly') return title\n if (languageDisplay === 'titleAndCode') return `${title} (${code.toUpperCase()})`\n return title\n}\n","import get from 'lodash-es/get.js'\n\n/**\n * Extracts a subset of values from a Sanity document based on a `select`\n * mapping (as configured in the plugin's `select` option).\n *\n * Each key in `select` becomes a key in the returned object, with its value\n * resolved from the document using the corresponding dot-path (via lodash `get`).\n *\n * Array values are filtered to remove incomplete references (objects with\n * `_type: 'reference'` but no `_ref`), since those represent empty reference\n * fields that should be ignored.\n *\n * Returns an empty object when either `select` or `document` is undefined.\n */\nexport const getSelectedValue = (\n select: Record<string, string> | undefined,\n document:\n | {\n [x: string]: unknown\n }\n | undefined,\n): Record<string, unknown> => {\n if (!select || !document) {\n return {}\n }\n\n const selection: Record<string, string> = select || {}\n const selectedValue: Record<string, unknown> = {}\n for (const [key, path] of Object.entries(selection)) {\n let value = get(document, path)\n if (Array.isArray(value)) {\n // If there are references in the array, ensure they have `_ref` set, otherwise they are considered empty and can safely be ignored\n value = value.filter((item) =>\n typeof item === 'object' ? item?._type === 'reference' && '_ref' in item : true,\n )\n }\n selectedValue[key] = value\n }\n\n return selectedValue\n}\n","import {useLanguageFilterStudioContext} from '@sanity/language-filter'\nimport type React from 'react'\nimport {createContext, use, useContext, useDeferredValue, useMemo} from 'react'\nimport {useClient, useWorkspace} from 'sanity'\nimport {useDocumentPane} from 'sanity/structure'\n\nimport {createCacheKey, createOrGetPromise, setFunctionCache} from '../cache'\nimport {CONFIG_DEFAULT} from '../constants'\nimport type {Language, PluginConfig} from '../types'\nimport {getSelectedValue} from './getSelectedValue'\n\n// This provider makes the plugin config available to all components in the document form\n// But with languages resolved and filtered languages updated base on @sanity/language-filter\n\nexport type InternationalizedArrayContextProps = Required<PluginConfig> & {\n languages: Language[]\n filteredLanguages: Language[]\n}\n\nconst InternationalizedArrayContext = createContext<InternationalizedArrayContextProps>({\n ...CONFIG_DEFAULT,\n languages: [],\n filteredLanguages: [],\n})\n\nexport function useInternationalizedArrayContext(): InternationalizedArrayContextProps {\n return useContext(InternationalizedArrayContext)\n}\n\ntype InternationalizedArrayProviderProps = {\n internationalizedArray: Required<PluginConfig>\n documentType: string\n}\n\nexport function InternationalizedArrayProvider(\n props: React.PropsWithChildren<InternationalizedArrayProviderProps>,\n): React.ReactElement {\n const {internationalizedArray, documentType} = props\n\n const client = useClient({apiVersion: internationalizedArray.apiVersion})\n const workspace = useWorkspace()\n const {formState} = useDocumentPane()\n const deferredDocument = useDeferredValue(formState?.value)\n const selectedValue = useMemo(\n () => getSelectedValue(internationalizedArray.select, deferredDocument),\n [internationalizedArray.select, deferredDocument],\n )\n\n // Use a stable workspace identifier to prevent unnecessary re-renders\n const workspaceId = useMemo(() => {\n // Use workspace name if available, otherwise create a stable hash\n if (workspace?.name) {\n return workspace.name\n }\n // Create a stable hash from workspace properties that matter for caching\n const workspaceKey = {\n name: workspace?.name,\n title: workspace?.title,\n // Add other stable properties as needed\n }\n return JSON.stringify(workspaceKey)\n }, [workspace])\n\n // Memoize the cache key to prevent expensive JSON.stringify calls\n const cacheKey = useMemo(\n () => createCacheKey(selectedValue, workspaceId),\n [selectedValue, workspaceId],\n )\n\n // Fetch or return languages\n const languagesPromise = useMemo(() => {\n if (Array.isArray(internationalizedArray.languages)) {\n return null // Return null for synchronous arrays\n }\n\n // Create or get cached promise for React.use\n return createOrGetPromise(async () => {\n if (typeof internationalizedArray.languages === 'function') {\n const result = await internationalizedArray.languages(client, selectedValue)\n // Populate function cache for use outside React context\n setFunctionCache(internationalizedArray.languages, selectedValue, result, workspaceId)\n return result\n }\n return internationalizedArray.languages\n }, cacheKey)\n }, [internationalizedArray, client, selectedValue, workspaceId, cacheKey])\n\n // Use React.use to handle the promise with Suspense, or return array directly\n const languages = languagesPromise\n ? use(languagesPromise)\n : // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n (internationalizedArray.languages as Language[])\n\n // Filter out some languages if language filter is enabled\n const {selectedLanguageIds, options: languageFilterOptions} = useLanguageFilterStudioContext()\n\n const filteredLanguages = useMemo(() => {\n const languageFilterEnabled = languageFilterOptions.documentTypes.includes(documentType)\n\n return languageFilterEnabled\n ? languages.filter((language) => selectedLanguageIds.includes(language.id))\n : languages\n }, [documentType, languageFilterOptions, languages, selectedLanguageIds])\n\n const context = useMemo(\n () => ({...internationalizedArray, languages, filteredLanguages}),\n [filteredLanguages, internationalizedArray, languages],\n )\n\n return (\n <InternationalizedArrayContext.Provider value={context}>\n {props.children}\n </InternationalizedArrayContext.Provider>\n )\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {Button, Grid} from '@sanity/ui'\n\nimport {MAX_COLUMNS} from '../constants'\nimport {getLanguageDisplay} from '../utils/getLanguageDisplay'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\n\ntype AddButtonsProps = {\n readOnly: boolean\n handleClick: (languageId: string) => void\n // Keys of languages that are already in use\n languagesInUse: string[]\n}\n\n/**\n * Renders a grid of \"add language\" buttons — one per configured language.\n *\n * Returns `null` when the `languages` array is empty.\n *\n * Each button is disabled when:\n * - `readOnly` is `true`, or\n * - the language already exists in the current `value` array\n * (matched via `LANGUAGE_FIELD_NAME`).\n *\n * The button label is formatted according to the `languageDisplay` setting\n * from the plugin context (e.g. code-only, title-only, or both).\n * An `AddIcon` is shown unless there are more languages than fit in one row\n * and the display mode is `'codeOnly'`.\n */\nfunction AddButtons(props: AddButtonsProps) {\n const {readOnly, languagesInUse, handleClick} = props\n const {languageDisplay, filteredLanguages: languages} = useInternationalizedArrayContext()\n\n if (!languages.length) return null\n\n return (\n <Grid\n gridTemplateColumns={Math.min(languages.length, MAX_COLUMNS[languageDisplay])}\n gap={2}\n data-testid=\"add-buttons-grid\"\n >\n {languages.map((language) => {\n const languageTitle: string = getLanguageDisplay(\n languageDisplay,\n language.title,\n language.id,\n )\n return (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n data-testid={`add-${language.id}`}\n disabled={readOnly || languagesInUse.includes(language.id)}\n text={languageTitle}\n // Only show plus icon if there's one row or less AND only showing codes\n icon={\n languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === 'codeOnly'\n ? undefined\n : AddIcon\n }\n value={language.id}\n onClick={() => handleClick(language.id)}\n />\n )\n })}\n </Grid>\n )\n}\n\nexport default AddButtons\n","import {Box, Stack, Text} from '@sanity/ui'\nimport {useToast} from '@sanity/ui/toast'\nimport {randomKey} from '@sanity/util/content'\nimport {type ReactElement, useCallback} from 'react'\nimport {\n type FormInsertPatch,\n type FormSetIfMissingPatch,\n insert,\n isSanityDocument,\n PatchEvent,\n setIfMissing,\n useGetFormValue,\n useSchema,\n} from 'sanity'\nimport {useDocumentPane} from 'sanity/structure'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {DocumentsToTranslate} from '../utils/getDocumentsToTranslate'\nimport {getDocumentsToTranslate} from '../utils/getDocumentsToTranslate'\nimport AddButtons from './AddButtons'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\n\n/**\n * Document-level \"add translation\" panel that appears outside individual\n * internationalized array fields (when `buttonLocations` includes `'document'`).\n *\n * Renders a heading and a row of per-language buttons. When a language button\n * is clicked the component:\n *\n * 1. Scans the current document for all internationalized array fields\n * using `getDocumentsToTranslate`.\n * 2. Filters out fields that already contain a translation for the selected\n * language, and deduplicates by field path.\n * 3. Shows an error toast if no eligible fields remain.\n * 4. Creates `setIfMissing` + `insert` patches to add the new language\n * entry to each eligible field, dispatching them via `onChange`.\n *\n * For Portable Text and other array-based value fields, the initial value\n * is set to an empty array (`[]`) rather than `undefined`.\n */\nexport default function DocumentAddButtons(): ReactElement {\n const getFormValue = useGetFormValue()\n const {filteredLanguages} = useInternationalizedArrayContext()\n\n const toast = useToast()\n const {onChange, formState} = useDocumentPane()\n const schema = useSchema()\n\n // Array-based types (e.g. Portable Text) need [] as initial value, not undefined\n const getInitialValueForType = useCallback(\n (typeName: string): unknown => {\n if (!typeName) return undefined\n\n // Extract the base type name from internationalized array type\n // e.g., \"internationalizedArrayBodyValue\" -> \"body\"\n const match = typeName.match(/^internationalizedArray(.+)Value$/)\n if (!match || !match[1]) return undefined\n\n const baseTypeName = match[1].charAt(0).toLowerCase() + match[1].slice(1)\n\n // Check if it's a known array-based type (Portable Text fields)\n const arrayBasedTypes = new Set(['body', 'htmlContent', 'blockContent', 'portableText'])\n if (arrayBasedTypes.has(baseTypeName)) {\n return []\n }\n\n // Try to look up the schema type to determine if it's an array\n const schemaType = schema.get(typeName)\n if (schemaType && 'fields' in schemaType) {\n // Check if this is an object type with a 'value' field\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const fields = schemaType.fields as Array<{\n name: string\n type?: {jsonType?: string; name?: string; type?: string; of?: unknown}\n }>\n const valueField = fields.find((f) => f.name === 'value')\n if (valueField) {\n const fieldType = valueField.type\n // Check if the value field is an array type\n if (\n fieldType?.jsonType === 'array' ||\n fieldType?.name === 'array' ||\n fieldType?.type === 'array' ||\n fieldType?.of !== undefined ||\n (fieldType?.name && arrayBasedTypes.has(fieldType.name))\n ) {\n return []\n }\n }\n }\n\n return undefined\n },\n [schema],\n )\n\n const handleDocumentButtonClick = useCallback(\n async (languageId: string) => {\n const value = getFormValue([])\n if (!isSanityDocument(value)) {\n toast.push({\n status: 'error',\n title: 'No document value found',\n })\n return\n }\n const documentsToTranslation = getDocumentsToTranslate(value, [])\n\n const alreadyTranslated = documentsToTranslation.filter(\n (translation) => translation?.[LANGUAGE_FIELD_NAME] === languageId,\n )\n const removeDuplicates = documentsToTranslation.reduce<DocumentsToTranslate[]>(\n (filteredTranslations, translation) => {\n if (\n alreadyTranslated.filter(\n (alreadyTranslation) => alreadyTranslation.pathString === translation.pathString,\n ).length > 0\n ) {\n return filteredTranslations\n }\n const translationAlreadyExists = filteredTranslations.filter(\n (filteredTranslation) => filteredTranslation.path === translation.path,\n )\n\n if (translationAlreadyExists.length > 0) {\n return filteredTranslations\n }\n filteredTranslations.push(translation)\n return filteredTranslations\n },\n [],\n )\n if (removeDuplicates.length === 0) {\n const language = filteredLanguages.find((l) => l.id === languageId)\n toast.push({\n status: 'warning',\n title: `No missing translations for ${language?.title || languageId} found.`,\n })\n return\n }\n\n // Build patches for each field missing the selected language\n const patches: (FormSetIfMissingPatch | FormInsertPatch)[] = []\n\n for (const toTranslate of removeDuplicates) {\n const path = toTranslate.path\n\n const initialValue = getInitialValueForType(toTranslate._type)\n\n const ifMissing = setIfMissing([], path)\n const insertValue = insert(\n [\n {\n _key: randomKey(),\n [LANGUAGE_FIELD_NAME]: languageId,\n _type: toTranslate._type,\n value: initialValue,\n },\n ],\n 'after',\n [...path, -1],\n )\n patches.push(ifMissing)\n patches.push(insertValue)\n }\n\n onChange(PatchEvent.from(patches.flat()))\n },\n [getInitialValueForType, onChange, toast, getFormValue, filteredLanguages],\n )\n return (\n <Stack gap={3} data-testid=\"document-add-buttons\">\n <Box>\n <Text size={1} weight=\"semibold\">\n Add translation to internationalized fields\n </Text>\n </Box>\n <AddButtons\n readOnly={Boolean(formState?.readOnly)}\n handleClick={handleDocumentButtonClick}\n languagesInUse={[]}\n />\n </Stack>\n )\n}\n","import {Stack} from '@sanity/ui'\nimport type {ObjectInputProps} from 'sanity'\n\nimport type {PluginConfig} from '../types'\nimport DocumentAddButtons from './DocumentAddButtons'\n\n/**\n * An input component for the root object of an internationalized array.\n * It renders the document add buttons if the buttonLocations include 'document'.\n */\nexport function InternationalizedArrayFormInput(\n props: ObjectInputProps & {pluginConfig: PluginConfig},\n) {\n const showDocumentButtons = props.pluginConfig?.buttonLocations?.includes('document')\n\n if (showDocumentButtons) {\n return (\n <Stack gap={5}>\n <DocumentAddButtons />\n {props.renderDefault(props)}\n </Stack>\n )\n }\n return props.renderDefault(props)\n}\n","import {isDocumentSchemaType, type ObjectField, type SchemaType} from 'sanity'\n\n/**\n * Returns true when a document schema contains any field (including nested\n * object/array item fields) whose type name starts with `internationalizedArray`.\n *\n * Traversal short-circuits on first match to avoid unnecessary work.\n */\nexport function hasInternationalizedArrayField(schemaType: SchemaType): boolean {\n if (!isDocumentSchemaType(schemaType)) {\n return false\n }\n\n return hasInternationalizedArrayInFields(schemaType.fields)\n}\n\nfunction hasInternationalizedArrayInFields(\n fields: ObjectField[],\n visited = new Set<unknown>(),\n): boolean {\n for (const field of fields) {\n if (visited.has(field.type)) {\n continue\n }\n visited.add(field.type)\n\n if (field.type.name.startsWith('internationalizedArray')) {\n return true\n }\n\n if (\n field.type.jsonType === 'object' &&\n hasInternationalizedArrayInFields(field.type.fields, visited)\n ) {\n return true\n }\n\n if (field.type.jsonType === 'array' && field.type.of.length > 0) {\n for (const item of field.type.of) {\n if (\n 'name' in item &&\n typeof item.name === 'string' &&\n item.name.startsWith('internationalizedArray')\n ) {\n return true\n }\n\n if ('fields' in item && Array.isArray(item.fields)) {\n if (visited.has(item)) {\n continue\n }\n visited.add(item)\n\n if (hasInternationalizedArrayInFields(item.fields, visited)) {\n return true\n }\n }\n }\n }\n }\n\n return false\n}\n","import {useSchema, type DocumentLayoutProps} from 'sanity'\n\nimport type {PluginConfig} from '../types'\nimport {hasInternationalizedArrayField} from '../utils/hasInternationalizedArrayField'\nimport {InternationalizedArrayProvider} from './InternationalizedArrayContext'\n\nexport function InternationalizedArrayLayout(\n props: DocumentLayoutProps & {pluginConfig: Required<PluginConfig>},\n) {\n const schema = useSchema()\n const schemaType = schema.get(props.documentType)\n\n if (!schemaType) {\n console.error(`Schema type not found: ${props.documentType}`)\n return props.renderDefault(props)\n }\n\n const hasInternationalizedArray = hasInternationalizedArrayField(schemaType)\n if (hasInternationalizedArray && props.pluginConfig.includeForDocumentType(props.documentType)) {\n return (\n <InternationalizedArrayProvider\n internationalizedArray={props.pluginConfig}\n documentType={props.documentType}\n >\n {props.renderDefault(props)}\n </InternationalizedArrayProvider>\n )\n }\n\n return props.renderDefault(props)\n}\n","import {useClient} from 'sanity'\n\nimport {createCacheKey, peek, preloadWithKey, setFunctionCache} from '../cache'\nimport type {PluginConfig} from '../types'\n\nexport default function Preload(props: Required<Pick<PluginConfig, 'apiVersion' | 'languages'>>) {\n const client = useClient({apiVersion: props.apiVersion})\n\n // Use the same cache key structure as the main component\n // This should match the main component when selectedValue is empty\n const cacheKey = createCacheKey({})\n\n if (!Array.isArray(peek({}))) {\n preloadWithKey(async () => {\n if (Array.isArray(props.languages)) {\n return props.languages\n }\n const result = await props.languages(client, {})\n // Populate function cache for sharing with other components\n // Use the same key structure as the main component\n setFunctionCache(props.languages, {}, result)\n return result\n }, cacheKey)\n }\n\n return null\n}\n","import {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {Language, InternationalizedArrayItem} from '../types'\n\n/**\n * Checks whether every language in the provided list has a corresponding entry\n * in the value array. It extracts language IDs from value items using\n * `LANGUAGE_FIELD_NAME` and compares them against the expected language IDs.\n *\n * Returns `true` only when the value array length matches the number of unique\n * languages and every value language ID is found in the languages list\n * (order does not matter). The length check ensures duplicates in value are\n * correctly rejected.\n */\nexport function checkAllLanguagesArePresent(\n languages: Language[],\n value: InternationalizedArrayItem[] | undefined,\n): boolean {\n const filteredLanguageIds = new Set(languages.map((l) => l.id))\n const languagesInUseIds = value ? value.map((v) => v[LANGUAGE_FIELD_NAME]) : []\n\n if (languagesInUseIds.length !== filteredLanguageIds.size) return false\n if (new Set(languagesInUseIds).size !== languagesInUseIds.length) return false\n return languagesInUseIds.every((key) => filteredLanguageIds.has(key))\n}\n","import {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {Language, InternationalizedArrayItem} from '../types'\n\n/**\n * Generates the label text for the \"add all / add missing languages\" button.\n *\n * - When there is no existing value: returns `\"Add {title} Field\"` for a\n * single language, or `\"Add all languages\"` for multiple.\n * - When some values already exist: returns `\"Add missing language\"` (singular)\n * or `\"Add missing languages\"` (plural) depending on how many are left.\n */\nexport function createAddAllTitle(\n value: InternationalizedArrayItem[] | undefined,\n languages: Language[],\n): string {\n if (value?.length) {\n const languagesInUse = new Set(value.map((item) => item[LANGUAGE_FIELD_NAME]))\n const missingCount = languages.filter((language) => !languagesInUse.has(language.id)).length\n return `Add missing ${missingCount === 1 ? `language` : `languages`}`\n }\n\n return languages.length === 1 && languages[0]\n ? `Add ${languages[0].title} Field`\n : `Add all languages`\n}\n","import type {LanguageFilterConfig} from '@sanity/language-filter'\nimport type {FieldDefinition, Rule, RuleTypeConstraint, SanityClient} from 'sanity'\nexport type Language = {\n id: Intl.UnicodeBCP47LocaleIdentifier\n title: string\n}\n\nexport type AllowedType = 'string' | 'number' | 'boolean' | 'text' | 'reference'\n\nexport type ArrayConfig = {\n name: string\n type: AllowedType\n languages: Language[]\n title?: string\n group?: string\n hidden?: boolean | (() => boolean)\n readOnly?: boolean | (() => boolean)\n validation?: Rule | Rule[]\n field?: {[key: string]: unknown; options: {[key: string]: unknown}}\n}\n\n/**\n * @deprecated Use InternationalizedArrayItem instead\n */\nexport type Value = {\n _key: string\n /** Language identifier (e.g., 'en', 'fr'). Added in v5. */\n language: string\n value?: unknown\n}\n\nexport function isInternationalizedArrayItemType(\n type: string,\n): type is InternationalizedArrayItem['_type'] {\n return type.startsWith('internationalizedArray') && type.endsWith('Value')\n}\n\nexport type InternationalizedArrayItem<T = unknown> = {\n _key: string\n value?: T\n /** Language identifier (e.g., 'en', 'fr'). Added in v5. */\n language: string\n /**\n * string that starts with \"internationalizedArray\" and ends with \"Value\"\n */\n _type: `internationalizedArray${string}Value`\n}\n\nexport type LanguageCallback = (\n client: SanityClient,\n selectedValue: Record<string, unknown>,\n) => Promise<Language[]>\n\nexport type LanguageDisplay = 'titleOnly' | 'codeOnly' | 'titleAndCode'\n\nexport type PluginConfig = {\n /**\n * https://www.sanity.io/docs/api-versioning\n * @defaultValue '2025-10-15'\n */\n apiVersion?: string\n /**\n * Specify fields that should be available in the language callback:\n * ```tsx\n * {\n * select: {\n * markets: 'markets'\n * },\n * languages: (client, {markets}) =>\n * query.fetch(groq`*[_type == \"language\" && market in $markets]{id,title}`, {markets})\n * }\n * ```\n */\n select?: Record<string, string>\n /**\n * You can give it an array of language definitions:\n * ```tsx\n * {\n * languages: [\n * {id: 'en', title: 'English'},\n * {id: 'fr', title: 'French'}\n * ]\n * }\n * ```\n * You can load them async by passing a function that returns a promise:\n * ```tsx\n * {\n * languages: async () => {\n * const response = await fetch('https://example.com/languages')\n * return response.json()\n * }\n * }\n * ```\n * You can query your dataset for languages::\n * ```tsx\n * {\n * languages: (client) =>\n * query.fetch(groq`*[_type == \"language\"]{id,title}`)\n * }\n * ```\n */\n languages: Language[] | LanguageCallback\n /**\n * You can specify a list of language IDs that should be pre-filled when creating a new document\n * ```tsx\n * {\n * defaultLanguages: ['en']\n * }\n * ```\n */\n defaultLanguages?: string[]\n /**\n * Can be a string matching core field types, as well as custom ones:\n * ```tsx\n * {\n * fieldTypes: [\n * \"date\", \"datetime\", \"file\", \"image\", \"number\", \"string\", \"text\", \"url\"\n * ]\n * }\n * ```\n * You can also define a type directly:\n * ```tsx\n * {\n * fieldTypes: [\n * defineField({\n * name: 'featuredProduct',\n * type: 'reference',\n * to: [{type: 'product'}]\n * hidden: (({document}) => !document?.title)\n * })\n * ]\n * }\n * ```\n */\n // oxlint-disable-next-line typescript-eslint/no-redundant-type-constituents\n fieldTypes: (string | RuleTypeConstraint | FieldDefinition)[]\n /**\n * Locations where the \"+ EN\" add language buttons are visible.\n * `fieldMenu` is one translate icon per field that opens a\n * language menu (compact; stable UI; no field actions). All locations are\n * additive, so `field`, `fieldMenu`, and `document` can be combined.\n * `unstable__fieldAction` is still accepted but crashes the editor from\n * plugin 4.0.4 onward on Studio 4 and above.\n * @defaultValue ['field']\n * */\n buttonLocations?: ('field' | 'fieldMenu' | 'unstable__fieldAction' | 'document')[]\n /**\n * Show or hide the \"Add all languages\" / \"Add missing languages\" control.\n * Under `field` this is the bar below the per-language buttons. Under\n * `fieldMenu` it is the bulk item inside the language menu.\n * @defaultValue true\n * */\n buttonAddAll?: boolean\n /**\n * Automatically reorder array items to match the configured `languages` order\n * when a document is opened.\n *\n * Disable this if you want to preserve a custom item order and avoid the\n * plugin writing a patch (which creates a draft / history entry) for published\n * documents whose order differs from the language config.\n *\n * @defaultValue true\n */\n restoreOrder?: boolean\n /**\n * How to display the languages on buttons and fields\n * @defaultValue 'code'\n * */\n languageDisplay?: LanguageDisplay\n /**\n * @internal\n * Function to determine if the plugin layout and root input should be included for a given document type.\n * @defaultValue (documentType) => documentType !== 'translation.metadata'\n * @example\n * {\n * includeForDocumentType: (documentType) => documentType === 'translation.metadata'\n * }\n */\n includeForDocumentType?: (documentType: string) => boolean\n /**\n * Configure the language filter for the plugin by providing the document types that should show the filter.\n * ```tsx\n * {\n * languageFilter: {\n * documentTypes: ['internationalizedPost', 'lesson'],\n * defaultLanguages: ['en']\n * }\n * }\n * ```\n */\n languageFilter?: {\n documentTypes: Required<LanguageFilterConfig>['documentTypes']\n defaultLanguages?: LanguageFilterConfig['defaultLanguages']\n }\n}\n","import {randomKey} from '@sanity/util/content'\nimport {type FormInsertPatch, insert, type Path} from 'sanity'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport {\n type Language,\n type InternationalizedArrayItem,\n isInternationalizedArrayItemType,\n} from '../types'\n\ntype AddConfig = {\n // New keys to add to the field\n addLanguageKeys: string[]\n // Schema of the current field\n schemaTypeName: string\n // All languages registered in the plugin\n languages: Language[]\n // Languages that are currently visible\n filteredLanguages: Language[]\n // Current value of the internationalizedArray field\n value?: InternationalizedArrayItem[]\n // Path to this item\n path?: Path\n}\n\n/**\n * Creates an array of Sanity `FormInsertPatch` objects that add new language\n * entries to an internationalized array field.\n *\n * If `addLanguageKeys` is provided, patches are created for those specific\n * language IDs. Otherwise, patches are created for all filtered languages\n * that are not already present in the current `value` array, for example when adding all missing languages.\n *\n * Each new item is assigned the correct `_type` (derived from the schema)\n * and the language identifier via `LANGUAGE_FIELD_NAME`.\n *\n * Insertions are ordered to maintain the same sequence as the master\n * `languages` list: each new item is inserted before the next existing\n * language in the value array, or appended at the end if no subsequent\n * language exists.\n */\nexport function createAddLanguagePatches(config: AddConfig): FormInsertPatch[] {\n const {addLanguageKeys, schemaTypeName, languages, filteredLanguages, value, path = []} = config\n\n const type = `${schemaTypeName}Value`\n if (!isInternationalizedArrayItemType(type)) {\n throw new Error(`Invalid internationalized array type: ${type}`)\n }\n const itemBase = {_type: type}\n\n // Create new items with random _key and language identifier\n const getNewItems = () => {\n if (Array.isArray(addLanguageKeys) && addLanguageKeys.length > 0) {\n return addLanguageKeys\n .filter((id) => {\n if (value?.length) {\n // Check if the language is already in the value and filter it out if it exists to avoid duplicates\n return !value.find((v) => v[LANGUAGE_FIELD_NAME] === id)\n }\n return true\n })\n .map((id) => Object.assign({}, itemBase, {_key: randomKey(), [LANGUAGE_FIELD_NAME]: id}))\n }\n\n return filteredLanguages\n .filter((language) => {\n return value?.length ? !value.find((v) => v[LANGUAGE_FIELD_NAME] === language.id) : true\n })\n .map((language) =>\n Object.assign({}, itemBase, {_key: randomKey(), [LANGUAGE_FIELD_NAME]: language.id}),\n )\n }\n const newItems = getNewItems()\n\n // Insert new items in the correct order\n const languagesInUse = value?.length ? value.map((v) => v) : []\n\n const insertions = newItems.map((item) => {\n // What's the original index of this language?\n const itemLanguage = item[LANGUAGE_FIELD_NAME]\n const languageIndex = languages.findIndex((l) => itemLanguage === l.id)\n\n // What languages are there beyond that index?\n const remainingLanguages = languages.slice(languageIndex + 1)\n\n // So what is the index in the current value array of the next language in the language array?\n const nextLanguageIndex = languagesInUse.findIndex((l) =>\n remainingLanguages.find((r) => r.id === l[LANGUAGE_FIELD_NAME]),\n )\n\n // Keep local state up to date incase multiple insertions are being made\n if (nextLanguageIndex < 0) {\n languagesInUse.push(item)\n } else {\n languagesInUse.splice(nextLanguageIndex, 0, item)\n }\n\n return nextLanguageIndex < 0\n ? // No next language (-1), add to end of array\n insert([item], 'after', [...path, nextLanguageIndex])\n : // Next language found, insert before that\n insert([item], 'before', [...path, nextLanguageIndex])\n })\n\n return insertions\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {TranslateIcon} from '@sanity/icons/Translate'\nimport {useCallback} from 'react'\nimport {\n defineDocumentFieldAction,\n type DocumentFieldActionItem,\n type DocumentFieldActionProps,\n PatchEvent,\n setIfMissing,\n useFormValue,\n} from 'sanity'\nimport {useDocumentPane} from 'sanity/structure'\n\nimport {useInternationalizedArrayContext} from '../components/InternationalizedArrayContext'\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {Language, InternationalizedArrayItem} from '../types'\nimport {checkAllLanguagesArePresent} from '../utils/checkAllLanguagesArePresent'\nimport {createAddAllTitle} from '../utils/createAddAllTitle'\nimport {createAddLanguagePatches} from '../utils/createAddLanguagePatches'\n\nconst createTranslateFieldActions: (\n fieldActionProps: DocumentFieldActionProps,\n context: {\n languages: Language[]\n filteredLanguages: Language[]\n },\n) => DocumentFieldActionItem[] = (fieldActionProps, {languages, filteredLanguages}) =>\n languages.map((language) => {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const value = useFormValue(fieldActionProps.path) as InternationalizedArrayItem[]\n const {onChange, formState} = useDocumentPane()\n const disabled =\n Boolean(formState?.readOnly) ||\n (value && Array.isArray(value)\n ? Boolean(value?.find((item) => item[LANGUAGE_FIELD_NAME] === language.id))\n : false)\n const hidden = !filteredLanguages.some((f) => f.id === language.id)\n\n const onAction = useCallback(() => {\n const {schemaType, path} = fieldActionProps\n\n const addLanguageKeys = [language.id]\n const patches = createAddLanguagePatches({\n addLanguageKeys,\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value,\n path,\n })\n\n onChange(PatchEvent.from([setIfMissing([], path), ...patches]))\n }, [language.id, value, onChange])\n\n return {\n type: 'action',\n icon: AddIcon,\n onAction,\n title: language.title,\n hidden,\n disabled,\n }\n })\n\nconst AddMissingTranslationsFieldAction: (\n fieldActionProps: DocumentFieldActionProps,\n context: {\n languages: Language[]\n filteredLanguages: Language[]\n },\n) => DocumentFieldActionItem = (fieldActionProps, {languages, filteredLanguages}) => {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const value = useFormValue(fieldActionProps.path) as InternationalizedArrayItem[]\n const {onChange, formState} = useDocumentPane()\n const disabled =\n Boolean(formState?.readOnly) || (value && value.length === filteredLanguages.length)\n const hidden = checkAllLanguagesArePresent(filteredLanguages, value)\n\n const onAction = useCallback(() => {\n const {schemaType, path} = fieldActionProps\n\n const addLanguageKeys: string[] = []\n const patches = createAddLanguagePatches({\n addLanguageKeys,\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value,\n path,\n })\n\n onChange(PatchEvent.from([setIfMissing([], path), ...patches]))\n }, [fieldActionProps, filteredLanguages, languages, onChange, value])\n\n return {\n type: 'action',\n icon: AddIcon,\n onAction,\n title: createAddAllTitle(value, filteredLanguages),\n disabled,\n hidden,\n }\n}\n\nexport const internationalizedArrayFieldAction = defineDocumentFieldAction({\n name: 'internationalizedArray',\n useAction(fieldActionProps) {\n const isInternationalizedArrayField =\n fieldActionProps?.schemaType?.type?.name.startsWith('internationalizedArray')\n const {languages, filteredLanguages} = useInternationalizedArrayContext()\n\n const translateFieldActions = createTranslateFieldActions(fieldActionProps, {\n languages,\n filteredLanguages,\n })\n\n return {\n type: 'group',\n icon: TranslateIcon,\n title: 'Add Translation',\n renderAsButton: true,\n children: isInternationalizedArrayField\n ? [\n ...translateFieldActions,\n AddMissingTranslationsFieldAction(fieldActionProps, {\n languages,\n filteredLanguages,\n }),\n ]\n : [],\n hidden: !isInternationalizedArrayField,\n }\n },\n})\n","import camelCase from 'lodash-es/camelCase.js'\nimport upperFirst from 'lodash-es/upperFirst.js'\n\n/**\n * Converts a string to PascalCase (e.g. `\"my-field\"` -> `\"MyField\"`).\n */\nexport function pascalCase(string: string): string {\n return upperFirst(camelCase(string))\n}\n\n/**\n * Generates the schema type name for an internationalized array field.\n *\n * - Without the value suffix: `\"internationalizedArray{PascalName}\"`\n * (used for the outer array type)\n * - With the value suffix: `\"internationalizedArray{PascalName}Value\"`\n * (used for the inner object type that wraps each language entry)\n *\n * For example, `createFieldName('block-content', true)` returns\n * `\"internationalizedArrayBlockContentValue\"`.\n */\nexport function createFieldName(name: string, addValue = false): string {\n return addValue\n ? [`internationalizedArray`, pascalCase(name), `Value`].join(``)\n : [`internationalizedArray`, pascalCase(name)].join(``)\n}\n","import type {ObjectSchemaType, FieldMember, FieldsetState} from 'sanity'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport {isInternationalizedArrayItemType, type Language} from '../types'\n\n/**\n * Default filter function for the internationalized array field.\n * It filter the field base on the `language` value of the object.\n */\nexport const internationalizedArrayLanguageFilter = (\n enclosingType: ObjectSchemaType,\n _member: FieldMember | FieldsetState,\n selectedLanguageIds: string[],\n parentValue: Record<string, unknown> | undefined,\n languages: Language[],\n) => {\n if (isInternationalizedArrayItemType(enclosingType.name)) {\n const language =\n typeof parentValue?.[LANGUAGE_FIELD_NAME] === 'string'\n ? parentValue?.[LANGUAGE_FIELD_NAME]\n : typeof parentValue?.['_key'] === 'string'\n ? parentValue?.['_key']\n : null\n\n const isAValidLanguage = language ? languages.find((l) => l.id === language) : true\n if (!isAValidLanguage) {\n // If it's not a valid language we should not hide it, because it needs to be surfaced to the user to fix it.\n // We need to update language-filter plugin so it doesn't hide the field later.\n return true\n }\n return language ? selectedLanguageIds.includes(language) : false\n }\n return true\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {TranslateIcon} from '@sanity/icons/Translate'\nimport {Button, Flex} from '@sanity/ui'\nimport {Menu, MenuButton, MenuDivider, MenuItem} from '@sanity/ui/menu'\nimport {useId} from 'react'\n\nimport {getLanguageDisplay} from '../utils/getLanguageDisplay'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\n\ntype CompactAddButtonProps = {\n readOnly: boolean\n handleClick: (languageId: string) => void\n languagesInUse: string[]\n onAddAll: () => void\n buttonAddAll: boolean\n addAllTitle: string\n allFilteredLanguagesArePresent: boolean\n}\n\n/**\n * One translate-icon button that opens a language menu — the `fieldMenu`\n * location. Compact, uses only stable `@sanity/ui`, and stays visible even\n * when every language is already present.\n */\nfunction CompactAddButton(props: CompactAddButtonProps) {\n const {\n readOnly,\n languagesInUse,\n handleClick,\n onAddAll,\n buttonAddAll,\n addAllTitle,\n allFilteredLanguagesArePresent,\n } = props\n const {languageDisplay, filteredLanguages: languages} = useInternationalizedArrayContext()\n const menuId = useId()\n\n if (!languages.length) return null\n\n return (\n <Flex justify=\"flex-end\" data-testid=\"field-menu\">\n <MenuButton\n id={menuId}\n popover={{portal: true, placement: 'bottom-end'}}\n button={\n <Button\n mode=\"bleed\"\n tone=\"default\"\n fontSize={1}\n padding={2}\n icon={TranslateIcon}\n aria-label=\"Add translation\"\n title=\"Add translation\"\n data-testid=\"add-translation-menu\"\n disabled={readOnly}\n />\n }\n menu={\n <Menu>\n {languages.map((language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n ))}\n {buttonAddAll ? (\n <>\n <MenuDivider />\n <MenuItem\n text={addAllTitle}\n icon={TranslateIcon}\n disabled={readOnly || allFilteredLanguagesArePresent}\n data-testid=\"field-menu-add-all\"\n onClick={onAddAll}\n />\n </>\n ) : null}\n </Menu>\n }\n />\n </Flex>\n )\n}\n\nexport default CompactAddButton\n","import {Card, Stack, Text} from '@sanity/ui'\nimport {Code} from '@sanity/ui/code'\nimport type React from 'react'\n\nconst schemaExample = {\n languages: [\n {id: 'en', title: 'English'},\n {id: 'no', title: 'Norsk'},\n ],\n}\n\nexport default function Feedback(): React.ReactElement {\n return (\n <Card tone=\"caution\" border radius={2} padding={3}>\n <Stack gap={4}>\n <Text>\n An array of language objects must be passed into the <code>internationalizedArray</code>{' '}\n helper function, each with an <code>id</code> and <code>title</code> field. Example:\n </Text>\n <Card padding={2} border radius={2}>\n <Code size={1} language=\"javascript\">\n {JSON.stringify(schemaExample, null, 2)}\n </Code>\n </Card>\n </Stack>\n </Card>\n )\n}\n","import {WarningOutlineIcon} from '@sanity/icons/WarningOutline'\nimport {Box, Card, Flex, Stack, Text} from '@sanity/ui'\nimport {type ReactElement} from 'react'\n\nimport type {InternationalizedArrayItem} from '../types'\n\nexport type MigrationBannerProps = {\n itemsNeedingMigration: InternationalizedArrayItem[]\n}\n\n/**\n * Migration banner component that displays a warning if the items need to be migrated to the v5 format.\n */\nexport function MigrationBanner({\n itemsNeedingMigration,\n}: MigrationBannerProps): ReactElement | null {\n // Don't render if no migration is needed\n if (!itemsNeedingMigration.length) {\n return null\n }\n\n return (\n <Card tone=\"caution\" padding={3} radius={2} border>\n <Flex gap={3} align=\"center\">\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack gap={2} flex={1}>\n <Text size={1} weight=\"semibold\">\n Data migration required\n </Text>\n <Text size={1} muted>\n {itemsNeedingMigration.length} item\n {itemsNeedingMigration.length === 1 ? '' : 's'}{' '}\n {itemsNeedingMigration.length === 1 ? 'needs' : 'need'} to be migrated to the v5 format.\n </Text>\n <Box marginTop={2}>\n <Text size={1}>\n This field still uses the v4 format where language is stored in <code>_key</code>.\n Migrate to the v5 format where language is stored in <code>language</code>.{' '}\n <a\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n href=\"https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/README.md#migrate-from-v4-to-v5\"\n >\n Learn more\n </a>\n .\n </Text>\n </Box>\n </Stack>\n </Flex>\n </Card>\n )\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {useLanguageFilterStudioContext} from '@sanity/language-filter'\nimport {Button, Card, Stack, Text} from '@sanity/ui'\nimport {useToast} from '@sanity/ui/toast'\nimport type React from 'react'\nimport {useCallback, useContext, useEffect, useMemo} from 'react'\nimport {\n type ArrayOfObjectsInputProps,\n ArrayOfObjectsItem,\n MemberItemError,\n set,\n setIfMissing,\n useFormValue,\n useGetFormValue,\n} from 'sanity'\nimport {EventsContext} from 'sanity/_singletons'\nimport {useDocumentPane} from 'sanity/structure'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {InternationalizedArrayItem} from '../types'\nimport {createAddAllTitle} from '../utils/createAddAllTitle'\nimport {createAddLanguagePatches} from '../utils/createAddLanguagePatches'\nimport {internationalizedArrayLanguageFilter} from '../utils/internationalizedArrayLanguageFilter'\nimport AddButtons from './AddButtons'\nimport CompactAddButton from './CompactAddButton'\nimport Feedback from './Feedback'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\nimport {MigrationBanner} from './MigrationBanner'\n\n/**\n * The events store has finished loading and recorded no history. That is a\n * brand-new document.\n *\n * `sanity/_singletons` is internal; this is the same context `useEvents()`\n * reads. Using the context directly avoids throwing when the events API is\n * off (legacy timeline has no `EventsProvider`).\n */\nfunction isPristineDocument(\n events: {events: readonly unknown[]; loading: boolean} | null,\n): boolean {\n if (!events || events.loading) {\n return false\n }\n return events.events.length === 0\n}\n\n/**\n * Main array input component for internationalized array fields.\n *\n * Replaces the default Sanity array input and manages the full lifecycle of\n * language entries:\n *\n * - **Language filter integration**: When `@sanity/language-filter` is active\n * for the current document type, array members are filtered to only show\n * languages matching the user's selection.\n * - **Adding languages**: Exposes per-language buttons, an optional compact\n * `fieldMenu`, and an \"Add all / Add missing languages\" button (controlled\n * by `buttonAddAll` and `buttonLocations`). Dispatches `setIfMissing` +\n * `insert` patches.\n * - **Default languages**: Automatically adds entries for languages listed in\n * `defaultLanguages` when those entries are missing. Seeds brand-new\n * documents once the events store reports they are pristine (no history),\n * and seeds persisted documents that already have a `_rev`. A document\n * that existed and was deleted is not pristine, so opening it — even in a\n * fresh pane — does not recreate it. Newly created documents stay\n * read-only until initial value templates resolve, and the field-level\n * `readOnly` prop can lag that document-level lock. Skipping the patch\n * until writable avoids \"Attempted to patch a read-only document\" toasts.\n * - **Ordering**: When `restoreOrder` is enabled (default), detects when value\n * items are out of order relative to the master `languages` list and\n * automatically re-sorts them. Set `restoreOrder: false` to keep the stored\n * order and avoid silent draft creation on open.\n * - **Validation**: Shows a `<Feedback>` component if the languages\n * configuration is invalid (e.g. missing `id` or `title`).\n * - **Empty state**: Displays a \"no translations\" message when the field has\n * no entries and the add buttons are not visible.\n */\nexport default function InternationalizedArray(\n props: ArrayOfObjectsInputProps,\n): React.ReactElement {\n const {members, value: _value, schemaType, onChange, readOnly: documentReadOnly} = props\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n const value = _value as InternationalizedArrayItem[]\n const itemsNeedingMigration = value?.filter((v) => !v[LANGUAGE_FIELD_NAME]) ?? []\n const shouldMigrateArray = itemsNeedingMigration.length > 0\n const toast = useToast()\n\n const getFormValue = useGetFormValue()\n const {\n languages,\n filteredLanguages,\n defaultLanguages,\n buttonAddAll,\n buttonLocations,\n restoreOrder,\n languageFilter: builtInLanguageFilter,\n } = useInternationalizedArrayContext()\n // Support updating the UI if languageFilter is installed\n const {selectedLanguageIds, options: languageFilterOptions} = useLanguageFilterStudioContext()\n const documentType = useFormValue(['_type'])\n const usingLanguageFilterPlugin =\n typeof documentType === 'string' && languageFilterOptions.documentTypes.includes(documentType)\n const usingBuiltInLanguageFilter =\n typeof documentType === 'string' && builtInLanguageFilter.documentTypes.includes(documentType)\n\n // TODO: Is this redundant? The filter plugin already filters members at its own level.\n const filteredMembers = useMemo(\n () =>\n usingLanguageFilterPlugin || usingBuiltInLanguageFilter\n ? members.filter((member) => {\n // This member is the outer object created by the plugin\n // Satisfy TS\n if (member.kind !== 'item') {\n return false\n }\n\n // This is the inner \"value\" field member created by this plugin\n const valueMember = member.item.members[0]\n\n // Satisfy TS\n if (!valueMember || valueMember.kind !== 'field') {\n return false\n }\n // The built-in filter receives the full languages list so it can\n // surface fields with invalid language IDs rather than hiding them.\n // The language filter plugin does not support this.\n return usingBuiltInLanguageFilter\n ? internationalizedArrayLanguageFilter(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n languages,\n )\n : languageFilterOptions.filterField(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n )\n })\n : members,\n [\n usingLanguageFilterPlugin,\n usingBuiltInLanguageFilter,\n members,\n selectedLanguageIds,\n languages,\n languageFilterOptions,\n ],\n )\n\n const {isDeleted, isDeleting, isInitialValueLoading, formState} = useDocumentPane()\n\n // Document-level locks (initial-value templates, permissions, history) are\n // not always reflected on the field's `readOnly` prop in the same tick as\n // the patch channel. Gating on both prevents toasts from auto-patches.\n const readOnly =\n Boolean(documentReadOnly) ||\n schemaType.readOnly === true ||\n Boolean(formState?.readOnly) ||\n Boolean(isInitialValueLoading)\n\n const handleAddLanguages = useCallback(\n (addLanguageKeys: string[] | string) => {\n if (readOnly) {\n return\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n const formValue = getFormValue(props.path) as InternationalizedArrayItem[]\n if (!filteredLanguages?.length) {\n return\n }\n\n const patches = createAddLanguagePatches({\n addLanguageKeys: Array.isArray(addLanguageKeys) ? addLanguageKeys : [addLanguageKeys],\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value: formValue,\n })\n\n onChange([setIfMissing([]), ...patches])\n },\n [filteredLanguages, languages, onChange, schemaType, getFormValue, props.path, readOnly],\n )\n\n // `_rev` means the document is in the dataset. No `_rev` is either a\n // brand-new form or a deleted one. The events store distinguishes those:\n // pristine (loaded, zero events) has never existed; any history means it\n // did — including a fresh open of a deleted id, where this pane never saw\n // a `_rev`.\n const documentExists = Boolean(useFormValue(['_rev']))\n const isPristine = isPristineDocument(useContext(EventsContext))\n\n // Create a stable dependency string that only changes when language keys change\n const languageKeysFromValue = value\n ?.map((v) => v[LANGUAGE_FIELD_NAME] ?? v._key)\n .filter(Boolean)\n .join(',')\n\n const addedLanguages = useMemo(() => {\n const languageKeys = languageKeysFromValue?.split(',') || []\n if (!languageKeys?.length) return []\n if (!languages?.length) return []\n\n return languages.filter((l) => languageKeys?.find((key) => key === l.id)).map((l) => l.id)\n }, [languageKeysFromValue, languages])\n\n useEffect(() => {\n const hasAddedDefaultLanguages = defaultLanguages\n .filter((language) => languages.find((l) => l.id === language))\n .every((language) => addedLanguages.includes(language))\n\n if (\n (isPristine || documentExists) &&\n !isDeleting &&\n !isDeleted &&\n !hasAddedDefaultLanguages &&\n !shouldMigrateArray &&\n !readOnly\n ) {\n const languagesToAdd = defaultLanguages\n .filter((language) => !addedLanguages.includes(language))\n .filter((language) => languages.find((l) => l.id === language))\n // Account for strict mode by scheduling the update.\n const timeout = setTimeout(() => {\n if (!readOnly) handleAddLanguages(languagesToAdd)\n })\n return () => clearTimeout(timeout)\n }\n return undefined\n }, [\n isPristine,\n documentExists,\n isDeleted,\n isDeleting,\n handleAddLanguages,\n defaultLanguages,\n addedLanguages,\n languages,\n readOnly,\n shouldMigrateArray,\n ])\n\n // NOTE: This is reordering and re-setting the whole array, it could be surgical\n const handleRestoreOrder = useCallback(() => {\n if (readOnly || !value?.length || !languages?.length) {\n return\n }\n\n // Create a new value array in the correct order\n // This would also strip out values that don't have a language as the key\n const updatedValue = value\n .reduce((acc, v) => {\n const newIndex = languages.findIndex((l) => l.id === v?.[LANGUAGE_FIELD_NAME])\n\n if (newIndex > -1) {\n acc[newIndex] = v\n }\n\n return acc\n }, [] as InternationalizedArrayItem[])\n .filter(Boolean)\n\n if (value?.length !== updatedValue.length) {\n toast.push({\n title: 'There was an error reordering languages',\n status: 'warning',\n })\n }\n\n onChange(set(updatedValue))\n }, [toast, languages, onChange, value, readOnly])\n\n const allKeysAreLanguages = useMemo(() => {\n if (!value?.length || !languages?.length) {\n return true\n }\n\n return value?.every((v) => languages.find((l) => l?.id === v?.[LANGUAGE_FIELD_NAME]))\n }, [value, languages])\n\n const languagesOutOfOrder = useMemo(() => {\n if (!value?.length || !addedLanguages.length) {\n return []\n }\n\n return value\n .map((v, vIndex) =>\n vIndex === addedLanguages.findIndex((language) => language === v[LANGUAGE_FIELD_NAME])\n ? null\n : v,\n )\n .filter(Boolean)\n }, [value, addedLanguages])\n\n const languagesAreValid = useMemo(\n () =>\n !languages?.length || (languages?.length && languages.every((item) => item.id && item.title)),\n [languages],\n )\n\n // Automatically restore order of fields (opt out with restoreOrder: false)\n useEffect(() => {\n if (restoreOrder && languagesOutOfOrder.length > 0 && allKeysAreLanguages && !readOnly) {\n handleRestoreOrder()\n }\n }, [restoreOrder, languagesOutOfOrder, allKeysAreLanguages, handleRestoreOrder, readOnly])\n\n const allFilteredLanguagesArePresent = useMemo(\n () => filteredLanguages.every((language) => addedLanguages.includes(language.id)),\n [filteredLanguages, addedLanguages],\n )\n const addAllMissingLanguages = useCallback(() => {\n handleAddLanguages(filteredLanguages.map((language) => language.id))\n }, [filteredLanguages, handleAddLanguages])\n\n if (!languagesAreValid) {\n return <Feedback />\n }\n\n const canAddLanguages = !shouldMigrateArray && filteredLanguages?.length > 0\n const showFieldMenu = canAddLanguages && buttonLocations.includes('fieldMenu')\n const showFieldButtons =\n canAddLanguages && buttonLocations.includes('field') && !allFilteredLanguagesArePresent\n const fieldHasMembers = members?.length > 0\n const addAllTitle = createAddAllTitle(value, filteredLanguages)\n\n const fieldButtons = showFieldButtons ? (\n <Stack gap={2}>\n <AddButtons\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n />\n {buttonAddAll ? (\n <Button\n tone=\"primary\"\n mode=\"ghost\"\n data-testid=\"add-all-languages\"\n disabled={readOnly || allFilteredLanguagesArePresent}\n icon={AddIcon}\n text={addAllTitle}\n onClick={addAllMissingLanguages}\n />\n ) : null}\n </Stack>\n ) : null\n\n return (\n <Stack gap={2}>\n {showFieldMenu ? (\n <CompactAddButton\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n onAddAll={addAllMissingLanguages}\n buttonAddAll={buttonAddAll}\n addAllTitle={addAllTitle}\n allFilteredLanguagesArePresent={allFilteredLanguagesArePresent}\n />\n ) : null}\n {filteredMembers.map((member) => {\n if (member.kind === 'item') {\n return <ArrayOfObjectsItem {...props} key={member.key} member={member} />\n }\n return <MemberItemError key={member.key} member={member} />\n })}\n <MigrationBanner itemsNeedingMigration={itemsNeedingMigration} />\n\n {/* Give some feedback in the UI so the field doesn't look \"missing\" */}\n {!showFieldMenu && !showFieldButtons && !fieldHasMembers ? (\n <Card border tone=\"transparent\" padding={3} radius={2}>\n <Text size={1}>This internationalized field currently has no translations.</Text>\n </Card>\n ) : null}\n\n {fieldButtons}\n </Stack>\n )\n}\n","import type {SchemaType} from 'sanity'\n\nimport type {ArrayFieldOptions} from '../schema/array'\n\nexport function getLanguagesFieldOption(\n schemaType: SchemaType | undefined,\n): ArrayFieldOptions['languages'] | undefined {\n if (!schemaType) {\n return undefined\n }\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const languagesOption = (schemaType.options as ArrayFieldOptions)?.languages\n if (languagesOption) {\n return languagesOption\n }\n return getLanguagesFieldOption(schemaType.type)\n}\n","import {defineField, type FieldDefinition, type FieldProps, type Rule} from 'sanity'\n\nimport {getFunctionCache, peek, setFunctionCache} from '../cache'\nimport {createFieldName} from '../components/createFieldName'\nimport {getSelectedValue} from '../components/getSelectedValue'\nimport InternationalizedArray from '../components/InternationalizedArray'\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {Language, LanguageCallback, InternationalizedArrayItem} from '../types'\nimport {getLanguagesFieldOption} from '../utils/getLanguagesFieldOption'\n\ntype ArrayFactoryConfig = {\n apiVersion: string\n select?: Record<string, string>\n languages: Language[] | LanguageCallback\n defaultLanguages?: string[]\n type: string | FieldDefinition\n}\n\nexport type ArrayFieldOptions = Pick<ArrayFactoryConfig, 'apiVersion' | 'select' | 'languages'>\n\nexport default (config: ArrayFactoryConfig) => {\n const {apiVersion, select, languages, type} = config\n const typeName = typeof type === `string` ? type : type.name\n const arrayName = createFieldName(typeName)\n const objectName = createFieldName(typeName, true)\n\n return defineField({\n name: arrayName,\n title: 'Internationalized array',\n type: 'array',\n components: {\n field: (props: FieldProps) =>\n props.renderDefault({\n ...props,\n // Reset the level to avoid nested styling\n level: 0,\n }),\n input: InternationalizedArray,\n },\n options: {\n // @ts-expect-error - these options are required for validation rules – not the custom input component\n apiVersion,\n select,\n languages,\n },\n of: [\n defineField({\n ...(typeof type === 'string' ? {} : type),\n name: objectName,\n type: objectName,\n }),\n ],\n // @ts-expect-error - fix typings\n validation: (rule: Rule) =>\n rule.custom<InternationalizedArrayItem[]>(async (value, context) => {\n if (!value || value.length === 0) {\n return true\n }\n\n // Check for items missing the language field (unmigrated data)\n const itemsMissingLanguage = value.filter(\n (item) => item && !item[LANGUAGE_FIELD_NAME] && item._key,\n )\n if (itemsMissingLanguage.length > 0) {\n return {\n message:\n 'Language is required for each array item. Run the migration to update your data from the old format.',\n paths: itemsMissingLanguage.flatMap((item) => [\n [{_key: item._key}],\n [{_key: item._key}, 'value'],\n ]),\n }\n }\n\n // Early return for simple cases to avoid expensive operations\n if (value.length === 1 && !value[0]?.[LANGUAGE_FIELD_NAME]) {\n return true\n }\n\n const selectedValue = getSelectedValue(select, context.document)\n const client = context.getClient({apiVersion})\n\n let contextLanguages: Language[] = []\n const languagesFieldOption = getLanguagesFieldOption(context?.type)\n\n if (Array.isArray(languagesFieldOption)) {\n contextLanguages = languagesFieldOption\n } else if (Array.isArray(peek(selectedValue))) {\n contextLanguages = peek(selectedValue) || []\n } else if (typeof languagesFieldOption === 'function') {\n // Try to get from function cache first (if it's the same function as the component)\n const cachedLanguages = getFunctionCache(languagesFieldOption, selectedValue)\n\n if (Array.isArray(cachedLanguages)) {\n contextLanguages = cachedLanguages\n } else {\n // Try suspend cache as fallback\n const suspendCachedLanguages = peek(selectedValue)\n if (Array.isArray(suspendCachedLanguages)) {\n contextLanguages = suspendCachedLanguages\n } else {\n // Only make the async call if we don't have cached data\n contextLanguages = await languagesFieldOption(client, selectedValue)\n // Cache the result for future validation calls\n setFunctionCache(languagesFieldOption, selectedValue, contextLanguages)\n }\n }\n }\n\n if (value && value.length > contextLanguages.length) {\n return `Cannot be more than ${\n contextLanguages.length === 1 ? `1 item` : `${contextLanguages.length} items`\n }`\n }\n\n // Create a Set for faster language ID lookups\n const languageIds = new Set(contextLanguages.map((lang) => lang.id))\n\n // Check for invalid language keys\n const nonLanguageKeys = value.filter(\n (item) => item?.[LANGUAGE_FIELD_NAME] && !languageIds.has(item[LANGUAGE_FIELD_NAME]),\n )\n if (nonLanguageKeys.length) {\n return {\n message: `Array item keys must be valid languages registered to the field type`,\n paths: nonLanguageKeys.map((item) => [{_key: item._key}]),\n }\n }\n\n // Check for duplicate language keys (more efficient)\n const seenLanguages = new Set<string>()\n const duplicateValues: InternationalizedArrayItem[] = []\n\n for (const item of value) {\n if (item?.[LANGUAGE_FIELD_NAME]) {\n if (seenLanguages.has(item[LANGUAGE_FIELD_NAME])) {\n duplicateValues.push(item)\n } else {\n seenLanguages.add(item[LANGUAGE_FIELD_NAME])\n }\n }\n }\n\n if (duplicateValues.length) {\n return {\n message: 'There can only be one field per language',\n paths: duplicateValues.map((item) => [{_key: item._key}]),\n }\n }\n\n return true\n }),\n })\n}\n","import type {CardTone} from '@sanity/ui'\nimport type {FormNodeValidation} from 'sanity'\n\n/**\n * Maps an array of Sanity form validation entries to a `@sanity/ui` `CardTone`\n * for visual feedback on internationalized array items.\n *\n * - Returns `'critical'` if any validation has `level: 'error'`\n * - Returns `'caution'` if any validation has `level: 'warning'` (and no errors)\n * - Returns `undefined` otherwise (no tone applied)\n *\n * Error level always takes precedence over warning.\n */\nexport function getToneFromValidation(validations: FormNodeValidation[]): CardTone | undefined {\n if (!validations?.length) {\n return undefined\n }\n\n const validationLevels = new Set(validations.map((v) => v.level))\n\n if (validationLevels.has('error')) {\n return `critical`\n } else if (validationLevels.has('warning')) {\n return `caution`\n }\n\n return undefined\n}\n","import {RemoveCircleIcon} from '@sanity/icons/RemoveCircle'\nimport {Box, Button, Card, Flex, Label, Spinner, Text} from '@sanity/ui'\nimport {Menu, MenuButton, MenuItem} from '@sanity/ui/menu'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport type React from 'react'\nimport {type ReactNode, useCallback, useMemo} from 'react'\nimport {type FormPatch, type ObjectItemProps, PatchEvent, type Path, useFormValue} from 'sanity'\nimport {set, unset} from 'sanity'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {InternationalizedArrayItem} from '../types'\nimport {getLanguageDisplay} from '../utils/getLanguageDisplay'\nimport {getToneFromValidation} from './getToneFromValidation'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\n\nfunction ChangeLanguageButton(props: {\n value: InternationalizedArrayItem\n path: Path\n onChange: (patch: FormPatch[] | PatchEvent | FormPatch) => void\n}): ReactNode {\n const {value, onChange, path} = props\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const parentValue = useFormValue(path.slice(0, -1)) as InternationalizedArrayItem[]\n const {languages} = useInternationalizedArrayContext()\n\n const languageKeysInUse = useMemo(\n () => parentValue?.map((v) => v[LANGUAGE_FIELD_NAME]) ?? [],\n [parentValue],\n )\n\n // Changes the key of this item, ideally to a valid language\n const handleKeyChange = (event: React.MouseEvent<HTMLButtonElement>): void => {\n const languageId = event?.currentTarget?.value\n\n if (!value || !languages?.length || !languages.find((l) => l.id === languageId)) {\n return\n }\n\n onChange([set(languageId, [LANGUAGE_FIELD_NAME])])\n }\n\n return (\n <MenuButton\n button={<Button fontSize={1} text={`Change \"${value[LANGUAGE_FIELD_NAME]}\"`} />}\n id={`${value[LANGUAGE_FIELD_NAME]}-change-key`}\n menu={\n <Menu>\n {languages.map((lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n ))}\n </Menu>\n }\n popover={{portal: true}}\n />\n )\n}\n\nfunction RemoveButton({\n isDefault,\n readOnly,\n onChange,\n}: {\n isDefault: boolean\n readOnly: boolean\n onChange: (patch: FormPatch[] | PatchEvent | FormPatch) => void\n}): ReactNode {\n // Removes this item from the array\n const handleUnset = (): void => {\n onChange(unset())\n }\n\n return (\n <Tooltip\n animate\n disabled={!isDefault}\n content={\n <Text muted size={1}>\n Can't remove default language\n </Text>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <span style={{paddingBottom: '2px'}}>\n <Button\n mode=\"bleed\"\n icon={RemoveCircleIcon}\n tone=\"critical\"\n disabled={readOnly || isDefault}\n onClick={handleUnset}\n />\n </span>\n </Tooltip>\n )\n}\n\n/**\n * Renders a single row of an internationalized array: a language label (or\n * \"Change\" menu for invalid keys), the value input, and a remove button.\n *\n * Key behaviours:\n * - Wraps `onChange` to intercept paste operations into empty Portable Text\n * fields, ensuring `setIfMissing` and correct path prefixing.\n * - Detects items needing migration (missing `LANGUAGE_FIELD_NAME`) and hides\n * the language label in that state.\n * - Shows a `MenuButton` with available languages when the current key is\n * not a valid language.\n * - Disables the remove button for languages listed in `defaultLanguages`.\n * - Shows a `Spinner` when languages have not been loaded yet.\n * - Applies a `CardTone` based on validation state via `getToneFromValidation`.\n */\nexport default function InternationalizedInput(\n props: ObjectItemProps<InternationalizedArrayItem>,\n): ReactNode {\n // Extract the original onChange to avoid dependency issues\n const originalOnChange = props.inputProps.onChange\n\n // Create a wrapped onChange handler to intercept patches for paste operations\n const wrappedOnChange = useCallback(\n (patches: unknown) => {\n // Ensure patches is an array before proceeding with paste logic\n // For single patch operations (like unset), pass through directly\n if (!Array.isArray(patches)) {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n }\n\n // Check if this is a paste operation into an empty or uninitialized Portable Text field\n const valueField = props.value?.value\n const isEmptyOrUndefined =\n valueField === undefined ||\n valueField === null ||\n (Array.isArray(valueField) && valueField.length === 0)\n\n if (isEmptyOrUndefined) {\n // Check for insert patches that are trying to operate on a non-existent structure\n const hasProblematicInsert = patches.some((patch: {type?: string; path?: unknown[]}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return false\n }\n\n // Look for insert patches targeting the value field or direct array index\n if (\n patch.type === 'insert' &&\n patch.path &&\n Array.isArray(patch.path) &&\n patch.path.length > 0\n ) {\n // The path might be ['value', index] or just [index] depending on context\n const isTargetingValue = patch.path[0] === 'value' || typeof patch.path[0] === 'number'\n return isTargetingValue\n }\n return false\n })\n\n if (hasProblematicInsert) {\n // First, ensure the value field exists as an empty array if it doesn't\n const initPatch =\n valueField === undefined ? {type: 'setIfMissing', path: ['value'], value: []} : null\n\n // Transform the patches to ensure they work with the nested structure\n const fixedPatches = patches.map(\n (patch: {type?: string; path?: unknown[]; [key: string]: unknown}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return patch\n }\n\n if (patch.type === 'insert' && patch.path && Array.isArray(patch.path)) {\n // Ensure the path is correct for the nested structure\n const fixedPath = patch.path[0] === 'value' ? patch.path : ['value', ...patch.path]\n const fixedPatch = {...patch, path: fixedPath}\n return fixedPatch\n }\n return patch\n },\n )\n\n // If we need to initialize the field, include that patch first\n const allPatches = initPatch ? [initPatch, ...fixedPatches] : fixedPatches\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(allPatches as Parameters<typeof originalOnChange>[0])\n }\n }\n\n // For all other cases, pass through unchanged\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n },\n [originalOnChange, props.value?.value],\n )\n\n // The parent array contains the languages from the plugin config\n const {languages, languageDisplay, defaultLanguages} = useInternationalizedArrayContext()\n\n const keyIsValid = languages?.length\n ? Boolean(languages.find((l) => l.id === props.value[LANGUAGE_FIELD_NAME]))\n : false\n\n const language = languages?.find((l) => l.id === props.value[LANGUAGE_FIELD_NAME])\n const languageTitle: string =\n keyIsValid && language ? getLanguageDisplay(languageDisplay, language.title, language.id) : ''\n\n const inlineProps = useMemo(\n () => ({\n ...props.inputProps,\n members: props.inputProps.members\n .filter((m) => m.kind === 'field' && m.name === 'value')\n .map((member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n }),\n value: props.value,\n // Use our wrapped onChange handler\n onChange: wrappedOnChange,\n }),\n [\n props.inputProps,\n props.value,\n wrappedOnChange,\n languageTitle,\n keyIsValid,\n originalOnChange,\n props.path,\n ],\n )\n\n const {validation, value, readOnly} = inlineProps\n\n if (!languages) {\n return <Spinner />\n }\n\n const isDefault = defaultLanguages.includes(value[LANGUAGE_FIELD_NAME])\n\n return (\n <Card paddingTop={2} tone={getToneFromValidation(validation)}>\n <Flex align=\"flex-end\" gap={2}>\n <Box flex={1}>{props.inputProps.renderInput(inlineProps)}</Box>\n <RemoveButton\n isDefault={isDefault}\n readOnly={Boolean(readOnly)}\n onChange={originalOnChange}\n />\n </Flex>\n </Card>\n )\n}\n","import {defineField, type FieldDefinition, type FieldProps} from 'sanity'\n\nimport {createFieldName} from '../components/createFieldName'\nimport InternationalizedInput from '../components/InternationalizedInput'\nimport {LANGUAGE_FIELD_NAME} from '../constants'\n\ntype ObjectFactoryConfig = {\n type: string | FieldDefinition\n}\n\nexport default (config: ObjectFactoryConfig) => {\n const {type} = config\n const typeName = typeof type === `string` ? type : type.name\n const objectName = createFieldName(typeName, true)\n\n return defineField({\n name: objectName,\n title: `Internationalized array ${typeName}`,\n type: 'object',\n components: {\n // @ts-expect-error - fix typings\n item: InternationalizedInput,\n field: (props: FieldProps) =>\n props.renderDefault({\n ...props,\n // Reset the level to avoid nested styling\n level: 0,\n }),\n },\n fields: [\n defineField({\n ...(typeof type === 'string' ? {type} : type),\n name: 'value',\n }),\n // Hidden language field - stores the language identifier (e.g., 'en', 'fr')\n // This replaces the previous pattern of storing language in _key\n defineField({\n name: 'language',\n type: 'string',\n hidden: true,\n validation: (Rule) => Rule.required(),\n }),\n ],\n preview: {\n select: {\n title: 'value',\n subtitle: LANGUAGE_FIELD_NAME,\n },\n },\n })\n}\n","import {languageFilter} from '@sanity/language-filter'\nimport {definePlugin, isObjectInputProps} from 'sanity'\n\nimport {InternationalizedArrayFormInput} from './components/InternationalizedArrayFormInput'\nimport {InternationalizedArrayLayout} from './components/InternationalizedArrayLayout'\nimport Preload from './components/Preload'\nimport {CONFIG_DEFAULT} from './constants'\nimport {internationalizedArrayFieldAction} from './fieldActions'\nimport array from './schema/array'\nimport object from './schema/object'\nimport type {PluginConfig} from './types'\nimport {hasInternationalizedArrayField} from './utils/hasInternationalizedArrayField'\n\nexport const internationalizedArray = definePlugin<PluginConfig>((config) => {\n const pluginConfig = {...CONFIG_DEFAULT, ...config}\n const {\n // oxlint-disable-next-line no-useless-default-assignment\n apiVersion = '2025-10-15',\n select,\n languages,\n fieldTypes,\n defaultLanguages,\n buttonLocations,\n languageFilter: languageFilterConfig,\n } = pluginConfig\n\n return {\n name: 'sanity-plugin-internationalized-array',\n // Preload languages for use throughout the Studio\n studio: Array.isArray(languages)\n ? undefined\n : {\n components: {\n layout: (props) => (\n <>\n <Preload apiVersion={apiVersion} languages={languages} />\n {props.renderDefault(props)}\n </>\n ),\n },\n },\n // Optional: render \"add language\" buttons as field actions\n document: {\n components: {\n unstable_layout: (props) => (\n <InternationalizedArrayLayout {...props} pluginConfig={pluginConfig} />\n ),\n },\n unstable_fieldActions: buttonLocations.includes('unstable__fieldAction')\n ? (prev) => [...prev, internationalizedArrayFieldAction]\n : undefined,\n },\n // Wrap document editor with a language provider\n form: {\n components: {\n input: (props) => {\n const isRootInput = props.id === 'root' && isObjectInputProps(props)\n\n if (!isRootInput) {\n return props.renderDefault(props)\n }\n\n const hasInternationalizedArray = hasInternationalizedArrayField(props.schemaType)\n\n if (\n hasInternationalizedArray &&\n pluginConfig.includeForDocumentType(props.schemaType.name)\n ) {\n return <InternationalizedArrayFormInput {...props} pluginConfig={pluginConfig} />\n }\n return props.renderDefault(props)\n },\n },\n },\n // Register custom schema types for the outer array and the inner object\n schema: {\n types: [\n ...fieldTypes.map((type) => array({type, apiVersion, select, languages, defaultLanguages})),\n ...fieldTypes.map((type) => object({type})),\n ],\n },\n plugins:\n languageFilterConfig?.documentTypes?.length > 0\n ? [\n languageFilter({\n documentTypes: languageFilterConfig.documentTypes,\n supportedLanguages: languages,\n defaultLanguages: languageFilterConfig.defaultLanguages,\n // This is specifically not adding filterField avoid the default filter field implementation.\n // It will be filtered in `internationalizedArray` component and will have access to the resolved languages.\n // Rendering the fields if the language key is incorrect, providing an improved UX\n }),\n ]\n : undefined,\n }\n})\n"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"index.js","names":["{apiVersion: internationalizedArray.apiVersion}","apiVersion","getSelectedValue(internationalizedArray.select, deferredDocument)","select","useMemo(\n () => getSelectedValue(internationalizedArray.select, deferredDocument),\n [internationalizedArray.select, deferredDocument],\n )","useMemo(() => {\n // Use workspace name if available, otherwise create a stable hash\n if (workspace?.name) {\n return workspace.name\n }\n // Create a stable hash from workspace properties that matter for caching\n const workspaceKey = {\n name: workspace?.name,\n title: workspace?.title,\n // Add other stable properties as needed\n }\n return JSON.stringify(workspaceKey)\n }, [workspace])","JSON.stringify(workspaceKey)","workspace?.name","workspace?.title","createCacheKey(selectedValue, workspaceId)","useMemo(\n () => createCacheKey(selectedValue, workspaceId),\n [selectedValue, workspaceId],\n )","useMemo(() => {\n if (Array.isArray(internationalizedArray.languages)) {\n return null // Return null for synchronous arrays\n }\n\n // Create or get cached promise for React.use\n return createOrGetPromise(async () => {\n if (typeof internationalizedArray.languages === 'function') {\n const result = await internationalizedArray.languages(client, selectedValue)\n // Populate function cache for use outside React context\n setFunctionCache(internationalizedArray.languages, selectedValue, result, workspaceId)\n return result\n }\n return internationalizedArray.languages\n }, cacheKey)\n }, [internationalizedArray, client, selectedValue, workspaceId, cacheKey])","async () => {\n if (typeof internationalizedArray.languages === 'function') {\n const result = await internationalizedArray.languages(client, selectedValue)\n // Populate function cache for use outside React context\n setFunctionCache(internationalizedArray.languages, selectedValue, result, workspaceId)\n return result\n }\n return internationalizedArray.languages\n }","internationalizedArray.languages","createOrGetPromise(async () => {\n if (typeof internationalizedArray.languages === 'function') {\n const result = await internationalizedArray.languages(client, selectedValue)\n // Populate function cache for use outside React context\n setFunctionCache(internationalizedArray.languages, selectedValue, result, workspaceId)\n return result\n }\n return internationalizedArray.languages\n }, cacheKey)","languageFilterOptions.documentTypes.includes(documentType)","documentTypes","languageFilterEnabled\n ? languages.filter((language) => selectedLanguageIds.includes(language.id))\n : languages","useMemo(() => {\n const languageFilterEnabled = languageFilterOptions.documentTypes.includes(documentType)\n\n return languageFilterEnabled\n ? languages.filter((language) => selectedLanguageIds.includes(language.id))\n : languages\n }, [documentType, languageFilterOptions, languages, selectedLanguageIds])","{...internationalizedArray, languages, filteredLanguages}","useMemo(\n () => ({...internationalizedArray, languages, filteredLanguages}),\n [filteredLanguages, internationalizedArray, languages],\n )","<InternationalizedArrayContext.Provider value={context}>\n {props.children}\n </InternationalizedArrayContext.Provider>","children","InternationalizedArrayContext.Provider","_c","languages.map((language) => {\n const languageTitle: string = getLanguageDisplay(\n languageDisplay,\n language.title,\n language.id,\n )\n return (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n data-testid={`add-${language.id}`}\n disabled={readOnly || languagesInUse.includes(language.id)}\n text={languageTitle}\n // Only show plus icon if there's one row or less AND only showing codes\n icon={\n languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === 'codeOnly'\n ? undefined\n : AddIcon\n }\n value={language.id}\n onClick={() => handleClick(language.id)}\n />\n )\n })","languages.length","(language) => {\n const languageTitle: string = getLanguageDisplay(\n languageDisplay,\n language.title,\n language.id,\n )\n return (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n data-testid={`add-${language.id}`}\n disabled={readOnly || languagesInUse.includes(language.id)}\n text={languageTitle}\n // Only show plus icon if there's one row or less AND only showing codes\n icon={\n languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === 'codeOnly'\n ? undefined\n : AddIcon\n }\n value={language.id}\n onClick={() => handleClick(language.id)}\n />\n )\n }","length","<Grid\n gridTemplateColumns={Math.min(languages.length, MAX_COLUMNS[languageDisplay])}\n gap={2}\n data-testid=\"add-buttons-grid\"\n >\n {languages.map((language) => {\n const languageTitle: string = getLanguageDisplay(\n languageDisplay,\n language.title,\n language.id,\n )\n return (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n data-testid={`add-${language.id}`}\n disabled={readOnly || languagesInUse.includes(language.id)}\n text={languageTitle}\n // Only show plus icon if there's one row or less AND only showing codes\n icon={\n languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === 'codeOnly'\n ? undefined\n : AddIcon\n }\n value={language.id}\n onClick={() => handleClick(language.id)}\n />\n )\n })}\n </Grid>","Math.min(languages.length, MAX_COLUMNS[languageDisplay])","_c","(typeName: string): unknown => {\n if (!typeName) return undefined\n\n // Extract the base type name from internationalized array type\n // e.g., \"internationalizedArrayBodyValue\" -> \"body\"\n const match = typeName.match(/^internationalizedArray(.+)Value$/)\n if (!match || !match[1]) return undefined\n\n const baseTypeName = match[1].charAt(0).toLowerCase() + match[1].slice(1)\n\n // Check if it's a known array-based type (Portable Text fields)\n const arrayBasedTypes = new Set(['body', 'htmlContent', 'blockContent', 'portableText'])\n if (arrayBasedTypes.has(baseTypeName)) {\n return []\n }\n\n // Try to look up the schema type to determine if it's an array\n const schemaType = schema.get(typeName)\n if (schemaType && 'fields' in schemaType) {\n // Check if this is an object type with a 'value' field\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const fields = schemaType.fields as Array<{\n name: string\n type?: {jsonType?: string; name?: string; type?: string; of?: unknown}\n }>\n const valueField = fields.find((f) => f.name === 'value')\n if (valueField) {\n const fieldType = valueField.type\n // Check if the value field is an array type\n if (\n fieldType?.jsonType === 'array' ||\n fieldType?.name === 'array' ||\n fieldType?.type === 'array' ||\n fieldType?.of !== undefined ||\n (fieldType?.name && arrayBasedTypes.has(fieldType.name))\n ) {\n return []\n }\n }\n }\n\n return undefined\n }","(f) => f.name === 'value'","useCallback(\n (typeName: string): unknown => {\n if (!typeName) return undefined\n\n // Extract the base type name from internationalized array type\n // e.g., \"internationalizedArrayBodyValue\" -> \"body\"\n const match = typeName.match(/^internationalizedArray(.+)Value$/)\n if (!match || !match[1]) return undefined\n\n const baseTypeName = match[1].charAt(0).toLowerCase() + match[1].slice(1)\n\n // Check if it's a known array-based type (Portable Text fields)\n const arrayBasedTypes = new Set(['body', 'htmlContent', 'blockContent', 'portableText'])\n if (arrayBasedTypes.has(baseTypeName)) {\n return []\n }\n\n // Try to look up the schema type to determine if it's an array\n const schemaType = schema.get(typeName)\n if (schemaType && 'fields' in schemaType) {\n // Check if this is an object type with a 'value' field\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const fields = schemaType.fields as Array<{\n name: string\n type?: {jsonType?: string; name?: string; type?: string; of?: unknown}\n }>\n const valueField = fields.find((f) => f.name === 'value')\n if (valueField) {\n const fieldType = valueField.type\n // Check if the value field is an array type\n if (\n fieldType?.jsonType === 'array' ||\n fieldType?.name === 'array' ||\n fieldType?.type === 'array' ||\n fieldType?.of !== undefined ||\n (fieldType?.name && arrayBasedTypes.has(fieldType.name))\n ) {\n return []\n }\n }\n }\n\n return undefined\n },\n [schema],\n )","async (languageId: string) => {\n const value = getFormValue([])\n if (!isSanityDocument(value)) {\n toast.push({\n status: 'error',\n title: 'No document value found',\n })\n return\n }\n const documentsToTranslation = getDocumentsToTranslate(value, [])\n\n const alreadyTranslated = documentsToTranslation.filter(\n (translation) => translation?.[LANGUAGE_FIELD_NAME] === languageId,\n )\n const removeDuplicates = documentsToTranslation.reduce<DocumentsToTranslate[]>(\n (filteredTranslations, translation) => {\n if (\n alreadyTranslated.filter(\n (alreadyTranslation) => alreadyTranslation.pathString === translation.pathString,\n ).length > 0\n ) {\n return filteredTranslations\n }\n const translationAlreadyExists = filteredTranslations.filter(\n (filteredTranslation) => filteredTranslation.path === translation.path,\n )\n\n if (translationAlreadyExists.length > 0) {\n return filteredTranslations\n }\n filteredTranslations.push(translation)\n return filteredTranslations\n },\n [],\n )\n if (removeDuplicates.length === 0) {\n const language = filteredLanguages.find((l) => l.id === languageId)\n toast.push({\n status: 'warning',\n title: `No missing translations for ${language?.title || languageId} found.`,\n })\n return\n }\n\n // Build patches for each field missing the selected language\n const patches: (FormSetIfMissingPatch | FormInsertPatch)[] = []\n\n for (const toTranslate of removeDuplicates) {\n const path = toTranslate.path\n\n const initialValue = getInitialValueForType(toTranslate._type)\n\n const ifMissing = setIfMissing([], path)\n const insertValue = insert(\n [\n {\n _key: randomKey(),\n [LANGUAGE_FIELD_NAME]: languageId,\n _type: toTranslate._type,\n value: initialValue,\n },\n ],\n 'after',\n [...path, -1],\n )\n patches.push(ifMissing)\n patches.push(insertValue)\n }\n\n onChange(PatchEvent.from(patches.flat()))\n }","translation","useCallback(\n async (languageId: string) => {\n const value = getFormValue([])\n if (!isSanityDocument(value)) {\n toast.push({\n status: 'error',\n title: 'No document value found',\n })\n return\n }\n const documentsToTranslation = getDocumentsToTranslate(value, [])\n\n const alreadyTranslated = documentsToTranslation.filter(\n (translation) => translation?.[LANGUAGE_FIELD_NAME] === languageId,\n )\n const removeDuplicates = documentsToTranslation.reduce<DocumentsToTranslate[]>(\n (filteredTranslations, translation) => {\n if (\n alreadyTranslated.filter(\n (alreadyTranslation) => alreadyTranslation.pathString === translation.pathString,\n ).length > 0\n ) {\n return filteredTranslations\n }\n const translationAlreadyExists = filteredTranslations.filter(\n (filteredTranslation) => filteredTranslation.path === translation.path,\n )\n\n if (translationAlreadyExists.length > 0) {\n return filteredTranslations\n }\n filteredTranslations.push(translation)\n return filteredTranslations\n },\n [],\n )\n if (removeDuplicates.length === 0) {\n const language = filteredLanguages.find((l) => l.id === languageId)\n toast.push({\n status: 'warning',\n title: `No missing translations for ${language?.title || languageId} found.`,\n })\n return\n }\n\n // Build patches for each field missing the selected language\n const patches: (FormSetIfMissingPatch | FormInsertPatch)[] = []\n\n for (const toTranslate of removeDuplicates) {\n const path = toTranslate.path\n\n const initialValue = getInitialValueForType(toTranslate._type)\n\n const ifMissing = setIfMissing([], path)\n const insertValue = insert(\n [\n {\n _key: randomKey(),\n [LANGUAGE_FIELD_NAME]: languageId,\n _type: toTranslate._type,\n value: initialValue,\n },\n ],\n 'after',\n [...path, -1],\n )\n patches.push(ifMissing)\n patches.push(insertValue)\n }\n\n onChange(PatchEvent.from(patches.flat()))\n },\n [getInitialValueForType, onChange, toast, getFormValue, filteredLanguages],\n )","<Box>\n <Text size={1} weight=\"semibold\">\n Add translation to internationalized fields\n </Text>\n </Box>","[]","<Stack gap={3} data-testid=\"document-add-buttons\">\n <Box>\n <Text size={1} weight=\"semibold\">\n Add translation to internationalized fields\n </Text>\n </Box>\n <AddButtons\n readOnly={Boolean(formState?.readOnly)}\n handleClick={handleDocumentButtonClick}\n languagesInUse={[]}\n />\n </Stack>","Boolean(formState?.readOnly)","_c","_temp","<DocumentAddButtons />","props.renderDefault(props)","props.renderDefault","<Stack gap={5}>\n <DocumentAddButtons />\n {props.renderDefault(props)}\n </Stack>","_c","props.renderDefault(props)","props.renderDefault","<InternationalizedArrayProvider\n internationalizedArray={props.pluginConfig}\n documentType={props.documentType}\n >\n {props.renderDefault(props)}\n </InternationalizedArrayProvider>","documentType","pluginConfig","props.pluginConfig","props.documentType","_c","{apiVersion: props.apiVersion}","apiVersion","_c","{portal: true, placement: 'bottom-end'}","<Button\n mode=\"bleed\"\n tone=\"default\"\n fontSize={1}\n padding={2}\n icon={TranslateIcon}\n aria-label=\"Add translation\"\n title=\"Add translation\"\n data-testid=\"add-translation-menu\"\n disabled={readOnly}\n />","languages.map((language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n ))","(language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n )","buttonAddAll ? (\n <>\n <MenuDivider />\n <MenuItem\n text={addAllTitle}\n icon={TranslateIcon}\n disabled={readOnly || allFilteredLanguagesArePresent}\n data-testid=\"field-menu-add-all\"\n onClick={onAddAll}\n />\n </>\n ) : null","<Menu>\n {languages.map((language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n ))}\n {buttonAddAll ? (\n <>\n <MenuDivider />\n <MenuItem\n text={addAllTitle}\n icon={TranslateIcon}\n disabled={readOnly || allFilteredLanguagesArePresent}\n data-testid=\"field-menu-add-all\"\n onClick={onAddAll}\n />\n </>\n ) : null}\n </Menu>","<Flex justify=\"flex-end\" data-testid=\"field-menu\">\n <MenuButton\n id={menuId}\n popover={{portal: true, placement: 'bottom-end'}}\n button={\n <Button\n mode=\"bleed\"\n tone=\"default\"\n fontSize={1}\n padding={2}\n icon={TranslateIcon}\n aria-label=\"Add translation\"\n title=\"Add translation\"\n data-testid=\"add-translation-menu\"\n disabled={readOnly}\n />\n }\n menu={\n <Menu>\n {languages.map((language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n ))}\n {buttonAddAll ? (\n <>\n <MenuDivider />\n <MenuItem\n text={addAllTitle}\n icon={TranslateIcon}\n disabled={readOnly || allFilteredLanguagesArePresent}\n data-testid=\"field-menu-add-all\"\n onClick={onAddAll}\n />\n </>\n ) : null}\n </Menu>\n }\n />\n </Flex>","_c","_Fragment","<code>internationalizedArray</code>","<code>id</code>","<Text>\n An array of language objects must be passed into the <code>internationalizedArray</code>{' '}\n helper function, each with an <code>id</code> and <code>title</code> field. Example:\n </Text>","<Card tone=\"caution\" border radius={2} padding={3}>\n <Stack gap={4}>\n <Text>\n An array of language objects must be passed into the <code>internationalizedArray</code>{' '}\n helper function, each with an <code>id</code> and <code>title</code> field. Example:\n </Text>\n <Card padding={2} border radius={2}>\n <Code size={1} language=\"javascript\">\n {JSON.stringify(schemaExample, null, 2)}\n </Code>\n </Card>\n </Stack>\n </Card>","_c","{\n itemsNeedingMigration,\n}: MigrationBannerProps","<Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>","<Text size={1} weight=\"semibold\">\n Data migration required\n </Text>","<Text size={1} muted>\n {itemsNeedingMigration.length} item\n {itemsNeedingMigration.length === 1 ? '' : 's'}{' '}\n {itemsNeedingMigration.length === 1 ? 'needs' : 'need'} to be migrated to the v5 format.\n </Text>","length","itemsNeedingMigration.length === 1 ? '' : 's'","itemsNeedingMigration.length === 1 ? 'needs' : 'need'","<code>_key</code>","<code>language</code>","<Box marginTop={2}>\n <Text size={1}>\n This field still uses the v4 format where language is stored in <code>_key</code>.\n Migrate to the v5 format where language is stored in <code>language</code>.{' '}\n <a\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n href=\"https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/README.md#migrate-from-v4-to-v5\"\n >\n Learn more\n </a>\n .\n </Text>\n </Box>","<Card tone=\"caution\" padding={3} radius={2} border>\n <Flex gap={3} align=\"center\">\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack gap={2} flex={1}>\n <Text size={1} weight=\"semibold\">\n Data migration required\n </Text>\n <Text size={1} muted>\n {itemsNeedingMigration.length} item\n {itemsNeedingMigration.length === 1 ? '' : 's'}{' '}\n {itemsNeedingMigration.length === 1 ? 'needs' : 'need'} to be migrated to the v5 format.\n </Text>\n <Box marginTop={2}>\n <Text size={1}>\n This field still uses the v4 format where language is stored in <code>_key</code>.\n Migrate to the v5 format where language is stored in <code>language</code>.{' '}\n <a\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n href=\"https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/README.md#migrate-from-v4-to-v5\"\n >\n Learn more\n </a>\n .\n </Text>\n </Box>\n </Stack>\n </Flex>\n </Card>","_c","value?.filter((v) => !v[LANGUAGE_FIELD_NAME]) ?? []","(v) => !v[LANGUAGE_FIELD_NAME]","value?.filter","['_type']","typeof documentType === 'string' && languageFilterOptions.documentTypes.includes(documentType)","languageFilterOptions.documentTypes","typeof documentType === 'string' && builtInLanguageFilter.documentTypes.includes(documentType)","builtInLanguageFilter.documentTypes","usingLanguageFilterPlugin || usingBuiltInLanguageFilter\n ? members.filter((member) => {\n // This member is the outer object created by the plugin\n // Satisfy TS\n if (member.kind !== 'item') {\n return false\n }\n\n // This is the inner \"value\" field member created by this plugin\n const valueMember = member.item.members[0]\n\n // Satisfy TS\n if (!valueMember || valueMember.kind !== 'field') {\n return false\n }\n // The built-in filter receives the full languages list so it can\n // surface fields with invalid language IDs rather than hiding them.\n // The language filter plugin does not support this.\n return usingBuiltInLanguageFilter\n ? internationalizedArrayLanguageFilter(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n languages,\n )\n : languageFilterOptions.filterField(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n )\n })\n : members","useMemo(\n () =>\n usingLanguageFilterPlugin || usingBuiltInLanguageFilter\n ? members.filter((member) => {\n // This member is the outer object created by the plugin\n // Satisfy TS\n if (member.kind !== 'item') {\n return false\n }\n\n // This is the inner \"value\" field member created by this plugin\n const valueMember = member.item.members[0]\n\n // Satisfy TS\n if (!valueMember || valueMember.kind !== 'field') {\n return false\n }\n // The built-in filter receives the full languages list so it can\n // surface fields with invalid language IDs rather than hiding them.\n // The language filter plugin does not support this.\n return usingBuiltInLanguageFilter\n ? internationalizedArrayLanguageFilter(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n languages,\n )\n : languageFilterOptions.filterField(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n )\n })\n : members,\n [\n usingLanguageFilterPlugin,\n usingBuiltInLanguageFilter,\n members,\n selectedLanguageIds,\n languages,\n languageFilterOptions,\n ],\n )","(addLanguageKeys: string[] | string) => {\n if (readOnly) {\n return\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n const formValue = getFormValue(props.path) as InternationalizedArrayItem[]\n if (!filteredLanguages?.length) {\n return\n }\n\n const patches = createAddLanguagePatches({\n addLanguageKeys: Array.isArray(addLanguageKeys) ? addLanguageKeys : [addLanguageKeys],\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value: formValue,\n })\n\n onChange([setIfMissing([]), ...patches])\n }","filteredLanguages?.length","path","schemaType.name","useCallback(\n (addLanguageKeys: string[] | string) => {\n if (readOnly) {\n return\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n const formValue = getFormValue(props.path) as InternationalizedArrayItem[]\n if (!filteredLanguages?.length) {\n return\n }\n\n const patches = createAddLanguagePatches({\n addLanguageKeys: Array.isArray(addLanguageKeys) ? addLanguageKeys : [addLanguageKeys],\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value: formValue,\n })\n\n onChange([setIfMissing([]), ...patches])\n },\n [filteredLanguages, languages, onChange, schemaType, getFormValue, props.path, readOnly],\n )","['_rev']","isPristineDocument(useContext(EventsContext))","useContext(EventsContext)","value\n ?.map((v) => v[LANGUAGE_FIELD_NAME] ?? v._key)\n .filter(Boolean)\n .join(',')","(v) => v[LANGUAGE_FIELD_NAME] ?? v._key","value\n ?.map","useMemo(() => {\n const languageKeys = languageKeysFromValue?.split(',') || []\n if (!languageKeys?.length) return []\n if (!languages?.length) return []\n\n return languages.filter((l) => languageKeys?.find((key) => key === l.id)).map((l) => l.id)\n }, [languageKeysFromValue, languages])","languageKeysFromValue?.split","languages?.length","[]","(l) => l.id","() => {\n const hasAddedDefaultLanguages = defaultLanguages\n .filter((language) => languages.find((l) => l.id === language))\n .every((language) => addedLanguages.includes(language))\n\n if (\n (isPristine || documentExists) &&\n !isDeleting &&\n !isDeleted &&\n !hasAddedDefaultLanguages &&\n !shouldMigrateArray &&\n !readOnly\n ) {\n const languagesToAdd = defaultLanguages\n .filter((language) => !addedLanguages.includes(language))\n .filter((language) => languages.find((l) => l.id === language))\n // Account for strict mode by scheduling the update.\n const timeout = setTimeout(() => {\n if (!readOnly) handleAddLanguages(languagesToAdd)\n })\n return () => clearTimeout(timeout)\n }\n return undefined\n }","[\n isPristine,\n documentExists,\n isDeleted,\n isDeleting,\n handleAddLanguages,\n defaultLanguages,\n addedLanguages,\n languages,\n readOnly,\n shouldMigrateArray,\n ]","l","language","() => {\n if (readOnly || !value?.length || !languages?.length) {\n return\n }\n\n // Create a new value array in the correct order\n // This would also strip out values that don't have a language as the key\n const updatedValue = value\n .reduce((acc, v) => {\n const newIndex = languages.findIndex((l) => l.id === v?.[LANGUAGE_FIELD_NAME])\n\n if (newIndex > -1) {\n acc[newIndex] = v\n }\n\n return acc\n }, [] as InternationalizedArrayItem[])\n .filter(Boolean)\n\n if (value?.length !== updatedValue.length) {\n toast.push({\n title: 'There was an error reordering languages',\n status: 'warning',\n })\n }\n\n onChange(set(updatedValue))\n }","value?.length","v","useCallback(() => {\n if (readOnly || !value?.length || !languages?.length) {\n return\n }\n\n // Create a new value array in the correct order\n // This would also strip out values that don't have a language as the key\n const updatedValue = value\n .reduce((acc, v) => {\n const newIndex = languages.findIndex((l) => l.id === v?.[LANGUAGE_FIELD_NAME])\n\n if (newIndex > -1) {\n acc[newIndex] = v\n }\n\n return acc\n }, [] as InternationalizedArrayItem[])\n .filter(Boolean)\n\n if (value?.length !== updatedValue.length) {\n toast.push({\n title: 'There was an error reordering languages',\n status: 'warning',\n })\n }\n\n onChange(set(updatedValue))\n }, [toast, languages, onChange, value, readOnly])","useMemo(() => {\n if (!value?.length || !languages?.length) {\n return true\n }\n\n return value?.every((v) => languages.find((l) => l?.id === v?.[LANGUAGE_FIELD_NAME]))\n }, [value, languages])","value?.every((v) => languages.find((l) => l?.id === v?.[LANGUAGE_FIELD_NAME]))","value?.every","useMemo(() => {\n if (!value?.length || !addedLanguages.length) {\n return []\n }\n\n return value\n .map((v, vIndex) =>\n vIndex === addedLanguages.findIndex((language) => language === v[LANGUAGE_FIELD_NAME])\n ? null\n : v,\n )\n .filter(Boolean)\n }, [value, addedLanguages])","value\n .map((v, vIndex) =>\n vIndex === addedLanguages.findIndex((language) => language === v[LANGUAGE_FIELD_NAME])\n ? null\n : v,\n )\n .filter(Boolean)","(v, vIndex) =>\n vIndex === addedLanguages.findIndex((language) => language === v[LANGUAGE_FIELD_NAME])\n ? null\n : v","(item) => item.id && item.title","() => {\n if (restoreOrder && languagesOutOfOrder.length > 0 && allKeysAreLanguages && !readOnly) {\n handleRestoreOrder()\n }\n }","[restoreOrder, languagesOutOfOrder, allKeysAreLanguages, handleRestoreOrder, readOnly]","languagesOutOfOrder.length","filteredLanguages.every((language) => addedLanguages.includes(language.id))","(language) => addedLanguages.includes(language.id)","useMemo(\n () => filteredLanguages.every((language) => addedLanguages.includes(language.id)),\n [filteredLanguages, addedLanguages],\n )","() => {\n handleAddLanguages(filteredLanguages.map((language) => language.id))\n }","(language) => language.id","useCallback(() => {\n handleAddLanguages(filteredLanguages.map((language) => language.id))\n }, [filteredLanguages, handleAddLanguages])","<Feedback />","canAddLanguages && buttonLocations.includes('fieldMenu')","canAddLanguages && buttonLocations.includes('field') && !allFilteredLanguagesArePresent","createAddAllTitle(value, filteredLanguages)","showFieldButtons ? (\n <Stack gap={2}>\n <AddButtons\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n />\n {buttonAddAll ? (\n <Button\n tone=\"primary\"\n mode=\"ghost\"\n data-testid=\"add-all-languages\"\n disabled={readOnly || allFilteredLanguagesArePresent}\n icon={AddIcon}\n text={addAllTitle}\n onClick={addAllMissingLanguages}\n />\n ) : null}\n </Stack>\n ) : null","showFieldMenu ? (\n <CompactAddButton\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n onAddAll={addAllMissingLanguages}\n buttonAddAll={buttonAddAll}\n addAllTitle={addAllTitle}\n allFilteredLanguagesArePresent={allFilteredLanguagesArePresent}\n />\n ) : null","filteredMembers.map((member) => {\n if (member.kind === 'item') {\n return <ArrayOfObjectsItem {...props} key={member.key} member={member} />\n }\n return <MemberItemError key={member.key} member={member} />\n })","(member) => {\n if (member.kind === 'item') {\n return <ArrayOfObjectsItem {...props} key={member.key} member={member} />\n }\n return <MemberItemError key={member.key} member={member} />\n }","member","<MigrationBanner itemsNeedingMigration={itemsNeedingMigration} />","!showFieldMenu && !showFieldButtons && !fieldHasMembers ? (\n <Card border tone=\"transparent\" padding={3} radius={2}>\n <Text size={1}>This internationalized field currently has no translations.</Text>\n </Card>\n ) : null","<Stack gap={2}>\n {showFieldMenu ? (\n <CompactAddButton\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n onAddAll={addAllMissingLanguages}\n buttonAddAll={buttonAddAll}\n addAllTitle={addAllTitle}\n allFilteredLanguagesArePresent={allFilteredLanguagesArePresent}\n />\n ) : null}\n {filteredMembers.map((member) => {\n if (member.kind === 'item') {\n return <ArrayOfObjectsItem {...props} key={member.key} member={member} />\n }\n return <MemberItemError key={member.key} member={member} />\n })}\n <MigrationBanner itemsNeedingMigration={itemsNeedingMigration} />\n\n {/* Give some feedback in the UI so the field doesn't look \"missing\" */}\n {!showFieldMenu && !showFieldButtons && !fieldHasMembers ? (\n <Card border tone=\"transparent\" padding={3} radius={2}>\n <Text size={1}>This internationalized field currently has no translations.</Text>\n </Card>\n ) : null}\n\n {fieldButtons}\n </Stack>","_c","_temp","_temp2","_temp3","_temp4","path.slice(0, -1)","parentValue?.map((v) => v[LANGUAGE_FIELD_NAME]) ?? []","(v) => v[LANGUAGE_FIELD_NAME]","parentValue?.map","useMemo(\n () => parentValue?.map((v) => v[LANGUAGE_FIELD_NAME]) ?? [],\n [parentValue],\n )","(event: React.MouseEvent<HTMLButtonElement>): void => {\n const languageId = event?.currentTarget?.value\n\n if (!value || !languages?.length || !languages.find((l) => l.id === languageId)) {\n return\n }\n\n onChange([set(languageId, [LANGUAGE_FIELD_NAME])])\n }","languages?.length","<Button fontSize={1} text={`Change \"${value[LANGUAGE_FIELD_NAME]}\"`} />","`Change \"${value[LANGUAGE_FIELD_NAME]}\"`","languages.map((lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n ))","(lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n )","<Menu>\n {languages.map((lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n ))}\n </Menu>","{portal: true}","<MenuButton\n button={<Button fontSize={1} text={`Change \"${value[LANGUAGE_FIELD_NAME]}\"`} />}\n id={`${value[LANGUAGE_FIELD_NAME]}-change-key`}\n menu={\n <Menu>\n {languages.map((lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n ))}\n </Menu>\n }\n popover={{portal: true}}\n />","`${value[LANGUAGE_FIELD_NAME]}-change-key`","{\n isDefault,\n readOnly,\n onChange,\n}: {\n isDefault: boolean\n readOnly: boolean\n onChange: (patch: FormPatch[] | PatchEvent | FormPatch) => void\n}","(): void => {\n onChange(unset())\n }","<Text muted size={1}>\n Can't remove default language\n </Text>","['right', 'left']","{paddingBottom: '2px'}","<span style={{paddingBottom: '2px'}}>\n <Button\n mode=\"bleed\"\n icon={RemoveCircleIcon}\n tone=\"critical\"\n disabled={readOnly || isDefault}\n onClick={handleUnset}\n />\n </span>","readOnly || isDefault","<Tooltip\n animate\n disabled={!isDefault}\n content={\n <Text muted size={1}>\n Can't remove default language\n </Text>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <span style={{paddingBottom: '2px'}}>\n <Button\n mode=\"bleed\"\n icon={RemoveCircleIcon}\n tone=\"critical\"\n disabled={readOnly || isDefault}\n onClick={handleUnset}\n />\n </span>\n </Tooltip>","!isDefault","(patches: unknown) => {\n // Ensure patches is an array before proceeding with paste logic\n // For single patch operations (like unset), pass through directly\n if (!Array.isArray(patches)) {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n }\n\n // Check if this is a paste operation into an empty or uninitialized Portable Text field\n const valueField = props.value?.value\n const isEmptyOrUndefined =\n valueField === undefined ||\n valueField === null ||\n (Array.isArray(valueField) && valueField.length === 0)\n\n if (isEmptyOrUndefined) {\n // Check for insert patches that are trying to operate on a non-existent structure\n const hasProblematicInsert = patches.some((patch: {type?: string; path?: unknown[]}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return false\n }\n\n // Look for insert patches targeting the value field or direct array index\n if (\n patch.type === 'insert' &&\n patch.path &&\n Array.isArray(patch.path) &&\n patch.path.length > 0\n ) {\n // The path might be ['value', index] or just [index] depending on context\n const isTargetingValue = patch.path[0] === 'value' || typeof patch.path[0] === 'number'\n return isTargetingValue\n }\n return false\n })\n\n if (hasProblematicInsert) {\n // First, ensure the value field exists as an empty array if it doesn't\n const initPatch =\n valueField === undefined ? {type: 'setIfMissing', path: ['value'], value: []} : null\n\n // Transform the patches to ensure they work with the nested structure\n const fixedPatches = patches.map(\n (patch: {type?: string; path?: unknown[]; [key: string]: unknown}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return patch\n }\n\n if (patch.type === 'insert' && patch.path && Array.isArray(patch.path)) {\n // Ensure the path is correct for the nested structure\n const fixedPath = patch.path[0] === 'value' ? patch.path : ['value', ...patch.path]\n const fixedPatch = {...patch, path: fixedPath}\n return fixedPatch\n }\n return patch\n },\n )\n\n // If we need to initialize the field, include that patch first\n const allPatches = initPatch ? [initPatch, ...fixedPatches] : fixedPatches\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(allPatches as Parameters<typeof originalOnChange>[0])\n }\n }\n\n // For all other cases, pass through unchanged\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n }","value","(patch: {type?: string; path?: unknown[]}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return false\n }\n\n // Look for insert patches targeting the value field or direct array index\n if (\n patch.type === 'insert' &&\n patch.path &&\n Array.isArray(patch.path) &&\n patch.path.length > 0\n ) {\n // The path might be ['value', index] or just [index] depending on context\n const isTargetingValue = patch.path[0] === 'value' || typeof patch.path[0] === 'number'\n return isTargetingValue\n }\n return false\n }","(patch: {type?: string; path?: unknown[]; [key: string]: unknown}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return patch\n }\n\n if (patch.type === 'insert' && patch.path && Array.isArray(patch.path)) {\n // Ensure the path is correct for the nested structure\n const fixedPath = patch.path[0] === 'value' ? patch.path : ['value', ...patch.path]\n const fixedPatch = {...patch, path: fixedPath}\n return fixedPatch\n }\n return patch\n }","useCallback(\n (patches: unknown) => {\n // Ensure patches is an array before proceeding with paste logic\n // For single patch operations (like unset), pass through directly\n if (!Array.isArray(patches)) {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n }\n\n // Check if this is a paste operation into an empty or uninitialized Portable Text field\n const valueField = props.value?.value\n const isEmptyOrUndefined =\n valueField === undefined ||\n valueField === null ||\n (Array.isArray(valueField) && valueField.length === 0)\n\n if (isEmptyOrUndefined) {\n // Check for insert patches that are trying to operate on a non-existent structure\n const hasProblematicInsert = patches.some((patch: {type?: string; path?: unknown[]}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return false\n }\n\n // Look for insert patches targeting the value field or direct array index\n if (\n patch.type === 'insert' &&\n patch.path &&\n Array.isArray(patch.path) &&\n patch.path.length > 0\n ) {\n // The path might be ['value', index] or just [index] depending on context\n const isTargetingValue = patch.path[0] === 'value' || typeof patch.path[0] === 'number'\n return isTargetingValue\n }\n return false\n })\n\n if (hasProblematicInsert) {\n // First, ensure the value field exists as an empty array if it doesn't\n const initPatch =\n valueField === undefined ? {type: 'setIfMissing', path: ['value'], value: []} : null\n\n // Transform the patches to ensure they work with the nested structure\n const fixedPatches = patches.map(\n (patch: {type?: string; path?: unknown[]; [key: string]: unknown}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return patch\n }\n\n if (patch.type === 'insert' && patch.path && Array.isArray(patch.path)) {\n // Ensure the path is correct for the nested structure\n const fixedPath = patch.path[0] === 'value' ? patch.path : ['value', ...patch.path]\n const fixedPatch = {...patch, path: fixedPath}\n return fixedPatch\n }\n return patch\n },\n )\n\n // If we need to initialize the field, include that patch first\n const allPatches = initPatch ? [initPatch, ...fixedPatches] : fixedPatches\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(allPatches as Parameters<typeof originalOnChange>[0])\n }\n }\n\n // For all other cases, pass through unchanged\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n },\n [originalOnChange, props.value?.value],\n )","languages?.length\n ? Boolean(languages.find((l) => l.id === props.value[LANGUAGE_FIELD_NAME]))\n : false","keyIsValid && language ? getLanguageDisplay(languageDisplay, language.title, language.id) : ''","languages?.find","l","props.inputProps.members\n .filter((m) => m.kind === 'field' && m.name === 'value')\n .map((member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n })","members","path","(member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n }","(m) => m.kind === 'field' && m.name === 'value'","{\n ...props.inputProps,\n members: props.inputProps.members\n .filter((m) => m.kind === 'field' && m.name === 'value')\n .map((member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n }),\n value: props.value,\n // Use our wrapped onChange handler\n onChange: wrappedOnChange,\n }","inputProps","props.inputProps","useMemo(\n () => ({\n ...props.inputProps,\n members: props.inputProps.members\n .filter((m) => m.kind === 'field' && m.name === 'value')\n .map((member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n }),\n value: props.value,\n // Use our wrapped onChange handler\n onChange: wrappedOnChange,\n }),\n [\n props.inputProps,\n props.value,\n wrappedOnChange,\n languageTitle,\n keyIsValid,\n originalOnChange,\n props.path,\n ],\n )","<Spinner />","defaultLanguages.includes(value[LANGUAGE_FIELD_NAME])","getToneFromValidation(validation)","props.inputProps.renderInput(inlineProps)","<Box flex={1}>{props.inputProps.renderInput(inlineProps)}</Box>","<RemoveButton\n isDefault={isDefault}\n readOnly={Boolean(readOnly)}\n onChange={originalOnChange}\n />","Boolean(readOnly)","<Flex align=\"flex-end\" gap={2}>\n <Box flex={1}>{props.inputProps.renderInput(inlineProps)}</Box>\n <RemoveButton\n isDefault={isDefault}\n readOnly={Boolean(readOnly)}\n onChange={originalOnChange}\n />\n </Flex>","<Card paddingTop={2} tone={getToneFromValidation(validation)}>\n <Flex align=\"flex-end\" gap={2}>\n <Box flex={1}>{props.inputProps.renderInput(inlineProps)}</Box>\n <RemoveButton\n isDefault={isDefault}\n readOnly={Boolean(readOnly)}\n onChange={originalOnChange}\n />\n </Flex>\n </Card>","patch","_c","_Fragment","array","object","\"language\"","\"_key\""],"sources":["../src/cache.ts","../src/constants.ts","../src/utils/getDocumentsToTranslate.ts","../src/utils/getLanguageDisplay.ts","../src/components/getSelectedValue.ts","../src/components/InternationalizedArrayContext.tsx","../src/components/AddButtons.tsx","../src/components/DocumentAddButtons.tsx","../src/components/InternationalizedArrayFormInput.tsx","../src/utils/hasInternationalizedArrayField.ts","../src/components/InternationalizedArrayLayout.tsx","../src/components/Preload.tsx","../src/utils/checkAllLanguagesArePresent.ts","../src/utils/createAddAllTitle.ts","../src/types.ts","../src/utils/createAddLanguagePatches.ts","../src/fieldActions/index.ts","../src/components/createFieldName.ts","../src/utils/internationalizedArrayLanguageFilter.ts","../src/components/CompactAddButton.tsx","../src/components/Feedback.tsx","../src/components/MigrationBanner.tsx","../src/components/InternationalizedArray.tsx","../src/utils/getLanguagesFieldOption.ts","../src/schema/array.ts","../src/components/getToneFromValidation.ts","../src/components/InternationalizedInput.tsx","../src/schema/object.ts","../src/plugin.tsx"],"sourcesContent":["import type {Language, LanguageCallback} from './types'\n\nconst namespace = 'sanity-plugin-internationalized-array'\n\nconst version = 'v1'\n\n// Cache for function keys to avoid recalculating them\nconst functionKeyCache = new WeakMap<LanguageCallback, string>()\n\n// Cache for React.use promises\nconst promiseCache = new Map<string, Promise<Language[]>>()\n\n// Cache for function references to enable sharing between same functions\nconst functionCache = new Map<string, Language[]>()\n\n// Helper to create a cache key string from an array\nfunction stringifyCacheKey(key: unknown[]): string {\n return JSON.stringify(key)\n}\n\n// Enhanced preload function that can use custom cache keys\nexport const preloadWithKey = (fn: () => Promise<Language[]>, key: (string | number)[]) => {\n const keyStr = stringifyCacheKey(key)\n if (!promiseCache.has(keyStr)) {\n promiseCache.set(keyStr, fn())\n }\n}\n\n// Cache busting: clear all promise caches\nexport const clear = () => {\n promiseCache.clear()\n}\n\n// Peeking into entries outside of suspense\nexport const peek = (selectedValue: Record<string, unknown>) => {\n const key = stringifyCacheKey([version, namespace, selectedValue])\n const promise = promiseCache.get(key)\n if (promise) {\n // Check if promise is resolved\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const status = (promise as any)._status\n if (status === 'fulfilled') {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return (promise as any)._value as Language[] | undefined\n }\n }\n return undefined\n}\n\n// Helper function to create a stable cache key that matches the component's key structure\nexport const createCacheKey = (selectedValue: Record<string, unknown>, workspaceId?: string) => {\n const selectedValueHash = JSON.stringify(selectedValue)\n return workspaceId\n ? [version, namespace, selectedValueHash, workspaceId]\n : [version, namespace, selectedValueHash]\n}\n\n// Create or get cached promise for React.use\nexport const createOrGetPromise = (\n fn: () => Promise<Language[]>,\n key: (string | number | Record<string, unknown>)[],\n): Promise<Language[]> => {\n const keyStr = stringifyCacheKey(key)\n if (promiseCache.has(keyStr)) {\n return promiseCache.get(keyStr)!\n }\n const promise = fn()\n promiseCache.set(keyStr, promise)\n return promise\n}\n\n// Generate a unique key for a function reference (cached for performance)\nconst getFunctionKey = (fn: LanguageCallback): string => {\n // Check if we already have a cached key for this function\n const cachedKey = functionKeyCache.get(fn)\n if (cachedKey) {\n return cachedKey\n }\n\n // Create a hash for functions (only when needed)\n const fnStr = fn.toString()\n let hash = 0\n // Only hash the first 100 characters for performance\n const maxLength = Math.min(fnStr.length, 100)\n for (let i = 0; i < maxLength; i++) {\n const char = fnStr.charCodeAt(i)\n hash = (hash << 5) - hash + char\n hash &= hash // Convert to 32-bit integer\n }\n const key = `anonymous_${Math.abs(hash)}`\n functionKeyCache.set(fn, key)\n return key\n}\n\n// Create a cache key that includes function identity\nconst createFunctionCacheKey = (\n fn: LanguageCallback,\n selectedValue: Record<string, unknown>,\n workspaceId?: string,\n): string => {\n const functionKey = getFunctionKey(fn)\n const selectedValueHash = JSON.stringify(selectedValue)\n return workspaceId\n ? `${functionKey}:${selectedValueHash}:${workspaceId}`\n : `${functionKey}:${selectedValueHash}`\n}\n\n// Function-aware cache operations\nexport const getFunctionCache = (\n fn: LanguageCallback,\n selectedValue: Record<string, unknown>,\n workspaceId?: string,\n): Language[] | undefined => {\n const key = createFunctionCacheKey(fn, selectedValue, workspaceId)\n return functionCache.get(key)\n}\n\nexport const setFunctionCache = (\n fn: LanguageCallback,\n selectedValue: Record<string, unknown>,\n languages: Language[],\n workspaceId?: string,\n): void => {\n const key = createFunctionCacheKey(fn, selectedValue, workspaceId)\n functionCache.set(key, languages)\n}\n","import type {PluginConfig} from './types'\n\n/**\n * The field name used to identify the language of an internationalized array item.\n *\n * In v4.x this was '_key', in v5+ this is 'language'.\n * ```ts\n * {\n * \"description\": [\n * {\n * \"_key\": \"kjjNvZHK8Y2QpTEf3K5jc\",\n * \"_type\": \"internationalizedArrayTextValue\",\n * \"language\": \"en\"\n * \"value\": \"This is the description in English\"\n * },\n * {\n * \"_key\": \"kjjNvZHK8Y2QpTEf3K5jc\",\n * \"_type\": \"internationalizedArrayTextValue\",\n * \"language\": \"es\"\n * \"value\": \"This is the description in Spanish\"\n * },\n * ]\n * }\n * ```\n */\nexport const LANGUAGE_FIELD_NAME = 'language' as const\n\nexport const MAX_COLUMNS = {\n codeOnly: 5,\n titleOnly: 4,\n titleAndCode: 3,\n}\n\nexport const CONFIG_DEFAULT: Required<PluginConfig> = {\n languages: [],\n select: {},\n defaultLanguages: [],\n fieldTypes: [],\n apiVersion: '2025-10-15',\n buttonLocations: ['field'],\n buttonAddAll: true,\n restoreOrder: true,\n languageDisplay: 'codeOnly',\n includeForDocumentType: (documentType) => documentType !== 'translation.metadata',\n languageFilter: {\n documentTypes: [],\n },\n}\n","import type {SanityDocument} from 'sanity'\n\nexport interface DocumentsToTranslate {\n path: (string | number)[]\n pathString: string\n _key: string\n /** Language identifier (e.g., 'en', 'fr'). Added in v5. */\n language: string\n _type: string\n [key: string]: unknown\n}\n\n/**\n * Recursively traverses a Sanity document (or any nested value) and collects\n * all internationalized array items found within it.\n *\n * An item is considered an internationalized array value when its `_type`\n * starts with `\"internationalizedArray\"` and ends with `\"Value\"`.\n *\n * The function walks through objects and arrays, skipping keys that start\n * with `_` (internal Sanity fields like `_id`, `_type`, `_rev`). Each\n * returned item includes the original properties plus `path` (array of\n * segments) and `pathString` (dot-joined) indicating where it was found.\n */\nexport const getDocumentsToTranslate = (\n // oxlint-disable-next-line typescript-eslint/no-redundant-type-constituents\n value: SanityDocument | unknown,\n rootPath: (string | number)[] = [],\n): DocumentsToTranslate[] => {\n if (Array.isArray(value)) {\n const arrayRootPath = [...rootPath]\n\n // if item contains internationalized return array\n const internationalizedValues = value.filter((item) => {\n if (Array.isArray(item)) return false\n\n if (typeof item === 'object') {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const type = item?._type as string | undefined\n return type?.startsWith('internationalizedArray') && type?.endsWith('Value')\n }\n return false\n })\n\n if (internationalizedValues.length > 0) {\n return internationalizedValues.map((internationalizedValue) => {\n return Object.assign({}, internationalizedValue, {\n path: arrayRootPath,\n pathString: arrayRootPath.join('.'),\n })\n })\n }\n\n if (value.length > 0) {\n return value.flatMap((item, index) =>\n getDocumentsToTranslate(item, [...arrayRootPath, index]),\n )\n }\n\n return []\n }\n if (typeof value === 'object' && value) {\n const startsWithUnderscoreRegex = /^_/\n const itemKeys = Object.keys(value).filter(\n (key) => !key.match(startsWithUnderscoreRegex),\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n ) as (keyof typeof value)[]\n\n return itemKeys.flatMap((item) => {\n const selectedValue = value[item] as unknown\n const path = [...rootPath, item]\n return getDocumentsToTranslate(selectedValue, path)\n })\n }\n return []\n}\n","import type {LanguageDisplay} from '../types'\n\n/**\n * Formats a language label for display in buttons and field headers\n * based on the configured `languageDisplay` mode:\n *\n * - `'codeOnly'` -> uppercase code, e.g. `\"EN\"`\n * - `'titleOnly'` -> title as-is, e.g. `\"English\"`\n * - `'titleAndCode'` -> title with uppercase code, e.g. `\"English (EN)\"`\n *\n * Falls back to `title` for any unrecognized display mode.\n */\nexport function getLanguageDisplay(\n languageDisplay: LanguageDisplay,\n title: string,\n code: string,\n): string {\n if (languageDisplay === 'codeOnly') return code.toUpperCase()\n if (languageDisplay === 'titleOnly') return title\n if (languageDisplay === 'titleAndCode') return `${title} (${code.toUpperCase()})`\n return title\n}\n","import get from 'lodash-es/get.js'\n\n/**\n * Extracts a subset of values from a Sanity document based on a `select`\n * mapping (as configured in the plugin's `select` option).\n *\n * Each key in `select` becomes a key in the returned object, with its value\n * resolved from the document using the corresponding dot-path (via lodash `get`).\n *\n * Array values are filtered to remove incomplete references (objects with\n * `_type: 'reference'` but no `_ref`), since those represent empty reference\n * fields that should be ignored.\n *\n * Returns an empty object when either `select` or `document` is undefined.\n */\nexport const getSelectedValue = (\n select: Record<string, string> | undefined,\n document:\n | {\n [x: string]: unknown\n }\n | undefined,\n): Record<string, unknown> => {\n if (!select || !document) {\n return {}\n }\n\n const selection: Record<string, string> = select || {}\n const selectedValue: Record<string, unknown> = {}\n for (const [key, path] of Object.entries(selection)) {\n let value = get(document, path)\n if (Array.isArray(value)) {\n // If there are references in the array, ensure they have `_ref` set, otherwise they are considered empty and can safely be ignored\n value = value.filter((item) =>\n typeof item === 'object' ? item?._type === 'reference' && '_ref' in item : true,\n )\n }\n selectedValue[key] = value\n }\n\n return selectedValue\n}\n","import {useLanguageFilterStudioContext} from '@sanity/language-filter'\nimport type React from 'react'\nimport {createContext, use, useContext, useDeferredValue, useMemo} from 'react'\nimport {useClient, useWorkspace} from 'sanity'\nimport {useDocumentPane} from 'sanity/structure'\n\nimport {createCacheKey, createOrGetPromise, setFunctionCache} from '../cache'\nimport {CONFIG_DEFAULT} from '../constants'\nimport type {Language, PluginConfig} from '../types'\nimport {getSelectedValue} from './getSelectedValue'\n\n// This provider makes the plugin config available to all components in the document form\n// But with languages resolved and filtered languages updated base on @sanity/language-filter\n\nexport type InternationalizedArrayContextProps = Required<PluginConfig> & {\n languages: Language[]\n filteredLanguages: Language[]\n}\n\nconst InternationalizedArrayContext = createContext<InternationalizedArrayContextProps>({\n ...CONFIG_DEFAULT,\n languages: [],\n filteredLanguages: [],\n})\n\nexport function useInternationalizedArrayContext(): InternationalizedArrayContextProps {\n return useContext(InternationalizedArrayContext)\n}\n\ntype InternationalizedArrayProviderProps = {\n internationalizedArray: Required<PluginConfig>\n documentType: string\n}\n\nexport function InternationalizedArrayProvider(\n props: React.PropsWithChildren<InternationalizedArrayProviderProps>,\n): React.ReactElement {\n const {internationalizedArray, documentType} = props\n\n const client = useClient({apiVersion: internationalizedArray.apiVersion})\n const workspace = useWorkspace()\n const {formState} = useDocumentPane()\n const deferredDocument = useDeferredValue(formState?.value)\n const selectedValue = useMemo(\n () => getSelectedValue(internationalizedArray.select, deferredDocument),\n [internationalizedArray.select, deferredDocument],\n )\n\n // Use a stable workspace identifier to prevent unnecessary re-renders\n const workspaceId = useMemo(() => {\n // Use workspace name if available, otherwise create a stable hash\n if (workspace?.name) {\n return workspace.name\n }\n // Create a stable hash from workspace properties that matter for caching\n const workspaceKey = {\n name: workspace?.name,\n title: workspace?.title,\n // Add other stable properties as needed\n }\n return JSON.stringify(workspaceKey)\n }, [workspace])\n\n // Memoize the cache key to prevent expensive JSON.stringify calls\n const cacheKey = useMemo(\n () => createCacheKey(selectedValue, workspaceId),\n [selectedValue, workspaceId],\n )\n\n // Fetch or return languages\n const languagesPromise = useMemo(() => {\n if (Array.isArray(internationalizedArray.languages)) {\n return null // Return null for synchronous arrays\n }\n\n // Create or get cached promise for React.use\n return createOrGetPromise(async () => {\n if (typeof internationalizedArray.languages === 'function') {\n const result = await internationalizedArray.languages(client, selectedValue)\n // Populate function cache for use outside React context\n setFunctionCache(internationalizedArray.languages, selectedValue, result, workspaceId)\n return result\n }\n return internationalizedArray.languages\n }, cacheKey)\n }, [internationalizedArray, client, selectedValue, workspaceId, cacheKey])\n\n // Use React.use to handle the promise with Suspense, or return array directly\n const languages = languagesPromise\n ? use(languagesPromise)\n : // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n (internationalizedArray.languages as Language[])\n\n // Filter out some languages if language filter is enabled\n const {selectedLanguageIds, options: languageFilterOptions} = useLanguageFilterStudioContext()\n\n const filteredLanguages = useMemo(() => {\n const languageFilterEnabled = languageFilterOptions.documentTypes.includes(documentType)\n\n return languageFilterEnabled\n ? languages.filter((language) => selectedLanguageIds.includes(language.id))\n : languages\n }, [documentType, languageFilterOptions, languages, selectedLanguageIds])\n\n const context = useMemo(\n () => ({...internationalizedArray, languages, filteredLanguages}),\n [filteredLanguages, internationalizedArray, languages],\n )\n\n return (\n <InternationalizedArrayContext.Provider value={context}>\n {props.children}\n </InternationalizedArrayContext.Provider>\n )\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {Button, Grid} from '@sanity/ui'\n\nimport {MAX_COLUMNS} from '../constants'\nimport {getLanguageDisplay} from '../utils/getLanguageDisplay'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\n\ntype AddButtonsProps = {\n readOnly: boolean\n handleClick: (languageId: string) => void\n // Keys of languages that are already in use\n languagesInUse: string[]\n}\n\n/**\n * Renders a grid of \"add language\" buttons — one per configured language.\n *\n * Returns `null` when the `languages` array is empty.\n *\n * Each button is disabled when:\n * - `readOnly` is `true`, or\n * - the language already exists in the current `value` array\n * (matched via `LANGUAGE_FIELD_NAME`).\n *\n * The button label is formatted according to the `languageDisplay` setting\n * from the plugin context (e.g. code-only, title-only, or both).\n * An `AddIcon` is shown unless there are more languages than fit in one row\n * and the display mode is `'codeOnly'`.\n */\nfunction AddButtons(props: AddButtonsProps) {\n const {readOnly, languagesInUse, handleClick} = props\n const {languageDisplay, filteredLanguages: languages} = useInternationalizedArrayContext()\n\n if (!languages.length) return null\n\n return (\n <Grid\n gridTemplateColumns={Math.min(languages.length, MAX_COLUMNS[languageDisplay])}\n gap={2}\n data-testid=\"add-buttons-grid\"\n >\n {languages.map((language) => {\n const languageTitle: string = getLanguageDisplay(\n languageDisplay,\n language.title,\n language.id,\n )\n return (\n <Button\n key={language.id}\n tone=\"primary\"\n mode=\"ghost\"\n fontSize={1}\n data-testid={`add-${language.id}`}\n disabled={readOnly || languagesInUse.includes(language.id)}\n text={languageTitle}\n // Only show plus icon if there's one row or less AND only showing codes\n icon={\n languages.length > MAX_COLUMNS[languageDisplay] && languageDisplay === 'codeOnly'\n ? undefined\n : AddIcon\n }\n value={language.id}\n onClick={() => handleClick(language.id)}\n />\n )\n })}\n </Grid>\n )\n}\n\nexport default AddButtons\n","import {Box, Stack, Text} from '@sanity/ui'\nimport {useToast} from '@sanity/ui/toast'\nimport {randomKey} from '@sanity/util/content'\nimport {type ReactElement, useCallback} from 'react'\nimport {\n type FormInsertPatch,\n type FormSetIfMissingPatch,\n insert,\n isSanityDocument,\n PatchEvent,\n setIfMissing,\n useGetFormValue,\n useSchema,\n} from 'sanity'\nimport {useDocumentPane} from 'sanity/structure'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {DocumentsToTranslate} from '../utils/getDocumentsToTranslate'\nimport {getDocumentsToTranslate} from '../utils/getDocumentsToTranslate'\nimport AddButtons from './AddButtons'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\n\n/**\n * Document-level \"add translation\" panel that appears outside individual\n * internationalized array fields (when `buttonLocations` includes `'document'`).\n *\n * Renders a heading and a row of per-language buttons. When a language button\n * is clicked the component:\n *\n * 1. Scans the current document for all internationalized array fields\n * using `getDocumentsToTranslate`.\n * 2. Filters out fields that already contain a translation for the selected\n * language, and deduplicates by field path.\n * 3. Shows an error toast if no eligible fields remain.\n * 4. Creates `setIfMissing` + `insert` patches to add the new language\n * entry to each eligible field, dispatching them via `onChange`.\n *\n * For Portable Text and other array-based value fields, the initial value\n * is set to an empty array (`[]`) rather than `undefined`.\n */\nexport default function DocumentAddButtons(): ReactElement {\n const getFormValue = useGetFormValue()\n const {filteredLanguages} = useInternationalizedArrayContext()\n\n const toast = useToast()\n const {onChange, formState} = useDocumentPane()\n const schema = useSchema()\n\n // Array-based types (e.g. Portable Text) need [] as initial value, not undefined\n const getInitialValueForType = useCallback(\n (typeName: string): unknown => {\n if (!typeName) return undefined\n\n // Extract the base type name from internationalized array type\n // e.g., \"internationalizedArrayBodyValue\" -> \"body\"\n const match = typeName.match(/^internationalizedArray(.+)Value$/)\n if (!match || !match[1]) return undefined\n\n const baseTypeName = match[1].charAt(0).toLowerCase() + match[1].slice(1)\n\n // Check if it's a known array-based type (Portable Text fields)\n const arrayBasedTypes = new Set(['body', 'htmlContent', 'blockContent', 'portableText'])\n if (arrayBasedTypes.has(baseTypeName)) {\n return []\n }\n\n // Try to look up the schema type to determine if it's an array\n const schemaType = schema.get(typeName)\n if (schemaType && 'fields' in schemaType) {\n // Check if this is an object type with a 'value' field\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const fields = schemaType.fields as Array<{\n name: string\n type?: {jsonType?: string; name?: string; type?: string; of?: unknown}\n }>\n const valueField = fields.find((f) => f.name === 'value')\n if (valueField) {\n const fieldType = valueField.type\n // Check if the value field is an array type\n if (\n fieldType?.jsonType === 'array' ||\n fieldType?.name === 'array' ||\n fieldType?.type === 'array' ||\n fieldType?.of !== undefined ||\n (fieldType?.name && arrayBasedTypes.has(fieldType.name))\n ) {\n return []\n }\n }\n }\n\n return undefined\n },\n [schema],\n )\n\n const handleDocumentButtonClick = useCallback(\n async (languageId: string) => {\n const value = getFormValue([])\n if (!isSanityDocument(value)) {\n toast.push({\n status: 'error',\n title: 'No document value found',\n })\n return\n }\n const documentsToTranslation = getDocumentsToTranslate(value, [])\n\n const alreadyTranslated = documentsToTranslation.filter(\n (translation) => translation?.[LANGUAGE_FIELD_NAME] === languageId,\n )\n const removeDuplicates = documentsToTranslation.reduce<DocumentsToTranslate[]>(\n (filteredTranslations, translation) => {\n if (\n alreadyTranslated.filter(\n (alreadyTranslation) => alreadyTranslation.pathString === translation.pathString,\n ).length > 0\n ) {\n return filteredTranslations\n }\n const translationAlreadyExists = filteredTranslations.filter(\n (filteredTranslation) => filteredTranslation.path === translation.path,\n )\n\n if (translationAlreadyExists.length > 0) {\n return filteredTranslations\n }\n filteredTranslations.push(translation)\n return filteredTranslations\n },\n [],\n )\n if (removeDuplicates.length === 0) {\n const language = filteredLanguages.find((l) => l.id === languageId)\n toast.push({\n status: 'warning',\n title: `No missing translations for ${language?.title || languageId} found.`,\n })\n return\n }\n\n // Build patches for each field missing the selected language\n const patches: (FormSetIfMissingPatch | FormInsertPatch)[] = []\n\n for (const toTranslate of removeDuplicates) {\n const path = toTranslate.path\n\n const initialValue = getInitialValueForType(toTranslate._type)\n\n const ifMissing = setIfMissing([], path)\n const insertValue = insert(\n [\n {\n _key: randomKey(),\n [LANGUAGE_FIELD_NAME]: languageId,\n _type: toTranslate._type,\n value: initialValue,\n },\n ],\n 'after',\n [...path, -1],\n )\n patches.push(ifMissing)\n patches.push(insertValue)\n }\n\n onChange(PatchEvent.from(patches.flat()))\n },\n [getInitialValueForType, onChange, toast, getFormValue, filteredLanguages],\n )\n return (\n <Stack gap={3} data-testid=\"document-add-buttons\">\n <Box>\n <Text size={1} weight=\"semibold\">\n Add translation to internationalized fields\n </Text>\n </Box>\n <AddButtons\n readOnly={Boolean(formState?.readOnly)}\n handleClick={handleDocumentButtonClick}\n languagesInUse={[]}\n />\n </Stack>\n )\n}\n","import {Stack} from '@sanity/ui'\nimport type {ObjectInputProps} from 'sanity'\n\nimport type {PluginConfig} from '../types'\nimport DocumentAddButtons from './DocumentAddButtons'\n\n/**\n * An input component for the root object of an internationalized array.\n * It renders the document add buttons if the buttonLocations include 'document'.\n */\nexport function InternationalizedArrayFormInput(\n props: ObjectInputProps & {pluginConfig: PluginConfig},\n) {\n const showDocumentButtons = props.pluginConfig?.buttonLocations?.includes('document')\n\n if (showDocumentButtons) {\n return (\n <Stack gap={5}>\n <DocumentAddButtons />\n {props.renderDefault(props)}\n </Stack>\n )\n }\n return props.renderDefault(props)\n}\n","import {isDocumentSchemaType, type ObjectField, type SchemaType} from 'sanity'\n\n/**\n * Returns true when a document schema contains any field (including nested\n * object/array item fields) whose type name starts with `internationalizedArray`.\n *\n * Traversal short-circuits on first match to avoid unnecessary work.\n */\nexport function hasInternationalizedArrayField(schemaType: SchemaType): boolean {\n if (!isDocumentSchemaType(schemaType)) {\n return false\n }\n\n return hasInternationalizedArrayInFields(schemaType.fields)\n}\n\nfunction hasInternationalizedArrayInFields(\n fields: ObjectField[],\n visited = new Set<unknown>(),\n): boolean {\n for (const field of fields) {\n if (visited.has(field.type)) {\n continue\n }\n visited.add(field.type)\n\n if (field.type.name.startsWith('internationalizedArray')) {\n return true\n }\n\n if (\n field.type.jsonType === 'object' &&\n hasInternationalizedArrayInFields(field.type.fields, visited)\n ) {\n return true\n }\n\n if (field.type.jsonType === 'array' && field.type.of.length > 0) {\n for (const item of field.type.of) {\n if (\n 'name' in item &&\n typeof item.name === 'string' &&\n item.name.startsWith('internationalizedArray')\n ) {\n return true\n }\n\n if ('fields' in item && Array.isArray(item.fields)) {\n if (visited.has(item)) {\n continue\n }\n visited.add(item)\n\n if (hasInternationalizedArrayInFields(item.fields, visited)) {\n return true\n }\n }\n }\n }\n }\n\n return false\n}\n","import {useSchema, type DocumentLayoutProps} from 'sanity'\n\nimport type {PluginConfig} from '../types'\nimport {hasInternationalizedArrayField} from '../utils/hasInternationalizedArrayField'\nimport {InternationalizedArrayProvider} from './InternationalizedArrayContext'\n\nexport function InternationalizedArrayLayout(\n props: DocumentLayoutProps & {pluginConfig: Required<PluginConfig>},\n) {\n const schema = useSchema()\n const schemaType = schema.get(props.documentType)\n\n if (!schemaType) {\n console.error(`Schema type not found: ${props.documentType}`)\n return props.renderDefault(props)\n }\n\n const hasInternationalizedArray = hasInternationalizedArrayField(schemaType)\n if (hasInternationalizedArray && props.pluginConfig.includeForDocumentType(props.documentType)) {\n return (\n <InternationalizedArrayProvider\n internationalizedArray={props.pluginConfig}\n documentType={props.documentType}\n >\n {props.renderDefault(props)}\n </InternationalizedArrayProvider>\n )\n }\n\n return props.renderDefault(props)\n}\n","import {useClient} from 'sanity'\n\nimport {createCacheKey, peek, preloadWithKey, setFunctionCache} from '../cache'\nimport type {PluginConfig} from '../types'\n\nexport default function Preload(props: Required<Pick<PluginConfig, 'apiVersion' | 'languages'>>) {\n const client = useClient({apiVersion: props.apiVersion})\n\n // Use the same cache key structure as the main component\n // This should match the main component when selectedValue is empty\n const cacheKey = createCacheKey({})\n\n if (!Array.isArray(peek({}))) {\n preloadWithKey(async () => {\n if (Array.isArray(props.languages)) {\n return props.languages\n }\n const result = await props.languages(client, {})\n // Populate function cache for sharing with other components\n // Use the same key structure as the main component\n setFunctionCache(props.languages, {}, result)\n return result\n }, cacheKey)\n }\n\n return null\n}\n","import {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {Language, InternationalizedArrayItem} from '../types'\n\n/**\n * Checks whether every language in the provided list has a corresponding entry\n * in the value array. It extracts language IDs from value items using\n * `LANGUAGE_FIELD_NAME` and compares them against the expected language IDs.\n *\n * Returns `true` only when the value array length matches the number of unique\n * languages and every value language ID is found in the languages list\n * (order does not matter). The length check ensures duplicates in value are\n * correctly rejected.\n */\nexport function checkAllLanguagesArePresent(\n languages: Language[],\n value: InternationalizedArrayItem[] | undefined,\n): boolean {\n const filteredLanguageIds = new Set(languages.map((l) => l.id))\n const languagesInUseIds = value ? value.map((v) => v[LANGUAGE_FIELD_NAME]) : []\n\n if (languagesInUseIds.length !== filteredLanguageIds.size) return false\n if (new Set(languagesInUseIds).size !== languagesInUseIds.length) return false\n return languagesInUseIds.every((key) => filteredLanguageIds.has(key))\n}\n","import {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {Language, InternationalizedArrayItem} from '../types'\n\n/**\n * Generates the label text for the \"add all / add missing languages\" button.\n *\n * - When there is no existing value: returns `\"Add {title} Field\"` for a\n * single language, or `\"Add all languages\"` for multiple.\n * - When some values already exist: returns `\"Add missing language\"` (singular)\n * or `\"Add missing languages\"` (plural) depending on how many are left.\n */\nexport function createAddAllTitle(\n value: InternationalizedArrayItem[] | undefined,\n languages: Language[],\n): string {\n if (value?.length) {\n const languagesInUse = new Set(value.map((item) => item[LANGUAGE_FIELD_NAME]))\n const missingCount = languages.filter((language) => !languagesInUse.has(language.id)).length\n return `Add missing ${missingCount === 1 ? `language` : `languages`}`\n }\n\n return languages.length === 1 && languages[0]\n ? `Add ${languages[0].title} Field`\n : `Add all languages`\n}\n","import type {LanguageFilterConfig} from '@sanity/language-filter'\nimport type {FieldDefinition, Rule, RuleTypeConstraint, SanityClient} from 'sanity'\nexport type Language = {\n id: Intl.UnicodeBCP47LocaleIdentifier\n title: string\n}\n\nexport type AllowedType = 'string' | 'number' | 'boolean' | 'text' | 'reference'\n\nexport type ArrayConfig = {\n name: string\n type: AllowedType\n languages: Language[]\n title?: string\n group?: string\n hidden?: boolean | (() => boolean)\n readOnly?: boolean | (() => boolean)\n validation?: Rule | Rule[]\n field?: {[key: string]: unknown; options: {[key: string]: unknown}}\n}\n\n/**\n * @deprecated Use InternationalizedArrayItem instead\n */\nexport type Value = {\n _key: string\n /** Language identifier (e.g., 'en', 'fr'). Added in v5. */\n language: string\n value?: unknown\n}\n\nexport function isInternationalizedArrayItemType(\n type: string,\n): type is InternationalizedArrayItem['_type'] {\n return type.startsWith('internationalizedArray') && type.endsWith('Value')\n}\n\nexport type InternationalizedArrayItem<T = unknown> = {\n _key: string\n value?: T\n /** Language identifier (e.g., 'en', 'fr'). Added in v5. */\n language: string\n /**\n * string that starts with \"internationalizedArray\" and ends with \"Value\"\n */\n _type: `internationalizedArray${string}Value`\n}\n\nexport type LanguageCallback = (\n client: SanityClient,\n selectedValue: Record<string, unknown>,\n) => Promise<Language[]>\n\nexport type LanguageDisplay = 'titleOnly' | 'codeOnly' | 'titleAndCode'\n\nexport type PluginConfig = {\n /**\n * https://www.sanity.io/docs/api-versioning\n * @defaultValue '2025-10-15'\n */\n apiVersion?: string\n /**\n * Specify fields that should be available in the language callback:\n * ```tsx\n * {\n * select: {\n * markets: 'markets'\n * },\n * languages: (client, {markets}) =>\n * query.fetch(groq`*[_type == \"language\" && market in $markets]{id,title}`, {markets})\n * }\n * ```\n */\n select?: Record<string, string>\n /**\n * You can give it an array of language definitions:\n * ```tsx\n * {\n * languages: [\n * {id: 'en', title: 'English'},\n * {id: 'fr', title: 'French'}\n * ]\n * }\n * ```\n * You can load them async by passing a function that returns a promise:\n * ```tsx\n * {\n * languages: async () => {\n * const response = await fetch('https://example.com/languages')\n * return response.json()\n * }\n * }\n * ```\n * You can query your dataset for languages::\n * ```tsx\n * {\n * languages: (client) =>\n * query.fetch(groq`*[_type == \"language\"]{id,title}`)\n * }\n * ```\n */\n languages: Language[] | LanguageCallback\n /**\n * You can specify a list of language IDs that should be pre-filled when creating a new document\n * ```tsx\n * {\n * defaultLanguages: ['en']\n * }\n * ```\n */\n defaultLanguages?: string[]\n /**\n * Can be a string matching core field types, as well as custom ones:\n * ```tsx\n * {\n * fieldTypes: [\n * \"date\", \"datetime\", \"file\", \"image\", \"number\", \"string\", \"text\", \"url\"\n * ]\n * }\n * ```\n * You can also define a type directly:\n * ```tsx\n * {\n * fieldTypes: [\n * defineField({\n * name: 'featuredProduct',\n * type: 'reference',\n * to: [{type: 'product'}]\n * hidden: (({document}) => !document?.title)\n * })\n * ]\n * }\n * ```\n */\n // oxlint-disable-next-line typescript-eslint/no-redundant-type-constituents\n fieldTypes: (string | RuleTypeConstraint | FieldDefinition)[]\n /**\n * Locations where the \"+ EN\" add language buttons are visible.\n * `fieldMenu` is one translate icon per field that opens a\n * language menu (compact; stable UI; no field actions). All locations are\n * additive, so `field`, `fieldMenu`, and `document` can be combined.\n * `unstable__fieldAction` is still accepted but crashes the editor from\n * plugin 4.0.4 onward on Studio 4 and above.\n * @defaultValue ['field']\n * */\n buttonLocations?: ('field' | 'fieldMenu' | 'unstable__fieldAction' | 'document')[]\n /**\n * Show or hide the \"Add all languages\" / \"Add missing languages\" control.\n * Under `field` this is the bar below the per-language buttons. Under\n * `fieldMenu` it is the bulk item inside the language menu.\n * @defaultValue true\n * */\n buttonAddAll?: boolean\n /**\n * Automatically reorder array items to match the configured `languages` order\n * when a document is opened.\n *\n * Disable this if you want to preserve a custom item order and avoid the\n * plugin writing a patch (which creates a draft / history entry) for published\n * documents whose order differs from the language config.\n *\n * @defaultValue true\n */\n restoreOrder?: boolean\n /**\n * How to display the languages on buttons and fields\n * @defaultValue 'code'\n * */\n languageDisplay?: LanguageDisplay\n /**\n * @internal\n * Function to determine if the plugin layout and root input should be included for a given document type.\n * @defaultValue (documentType) => documentType !== 'translation.metadata'\n * @example\n * {\n * includeForDocumentType: (documentType) => documentType === 'translation.metadata'\n * }\n */\n includeForDocumentType?: (documentType: string) => boolean\n /**\n * Configure the language filter for the plugin by providing the document types that should show the filter.\n * ```tsx\n * {\n * languageFilter: {\n * documentTypes: ['internationalizedPost', 'lesson'],\n * defaultLanguages: ['en']\n * }\n * }\n * ```\n */\n languageFilter?: {\n documentTypes: Required<LanguageFilterConfig>['documentTypes']\n defaultLanguages?: LanguageFilterConfig['defaultLanguages']\n }\n}\n","import {randomKey} from '@sanity/util/content'\nimport {type FormInsertPatch, insert, type Path} from 'sanity'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport {\n type Language,\n type InternationalizedArrayItem,\n isInternationalizedArrayItemType,\n} from '../types'\n\ntype AddConfig = {\n // New keys to add to the field\n addLanguageKeys: string[]\n // Schema of the current field\n schemaTypeName: string\n // All languages registered in the plugin\n languages: Language[]\n // Languages that are currently visible\n filteredLanguages: Language[]\n // Current value of the internationalizedArray field\n value?: InternationalizedArrayItem[]\n // Path to this item\n path?: Path\n}\n\n/**\n * Creates an array of Sanity `FormInsertPatch` objects that add new language\n * entries to an internationalized array field.\n *\n * If `addLanguageKeys` is provided, patches are created for those specific\n * language IDs. Otherwise, patches are created for all filtered languages\n * that are not already present in the current `value` array, for example when adding all missing languages.\n *\n * Each new item is assigned the correct `_type` (derived from the schema)\n * and the language identifier via `LANGUAGE_FIELD_NAME`.\n *\n * Insertions are ordered to maintain the same sequence as the master\n * `languages` list: each new item is inserted before the next existing\n * language in the value array, or appended at the end if no subsequent\n * language exists.\n */\nexport function createAddLanguagePatches(config: AddConfig): FormInsertPatch[] {\n const {addLanguageKeys, schemaTypeName, languages, filteredLanguages, value, path = []} = config\n\n const type = `${schemaTypeName}Value`\n if (!isInternationalizedArrayItemType(type)) {\n throw new Error(`Invalid internationalized array type: ${type}`)\n }\n const itemBase = {_type: type}\n\n // Create new items with random _key and language identifier\n const getNewItems = () => {\n if (Array.isArray(addLanguageKeys) && addLanguageKeys.length > 0) {\n return addLanguageKeys\n .filter((id) => {\n if (value?.length) {\n // Check if the language is already in the value and filter it out if it exists to avoid duplicates\n return !value.find((v) => v[LANGUAGE_FIELD_NAME] === id)\n }\n return true\n })\n .map((id) => Object.assign({}, itemBase, {_key: randomKey(), [LANGUAGE_FIELD_NAME]: id}))\n }\n\n return filteredLanguages\n .filter((language) => {\n return value?.length ? !value.find((v) => v[LANGUAGE_FIELD_NAME] === language.id) : true\n })\n .map((language) =>\n Object.assign({}, itemBase, {_key: randomKey(), [LANGUAGE_FIELD_NAME]: language.id}),\n )\n }\n const newItems = getNewItems()\n\n // Insert new items in the correct order\n const languagesInUse = value?.length ? value.map((v) => v) : []\n\n const insertions = newItems.map((item) => {\n // What's the original index of this language?\n const itemLanguage = item[LANGUAGE_FIELD_NAME]\n const languageIndex = languages.findIndex((l) => itemLanguage === l.id)\n\n // What languages are there beyond that index?\n const remainingLanguages = languages.slice(languageIndex + 1)\n\n // So what is the index in the current value array of the next language in the language array?\n const nextLanguageIndex = languagesInUse.findIndex((l) =>\n remainingLanguages.find((r) => r.id === l[LANGUAGE_FIELD_NAME]),\n )\n\n // Keep local state up to date incase multiple insertions are being made\n if (nextLanguageIndex < 0) {\n languagesInUse.push(item)\n } else {\n languagesInUse.splice(nextLanguageIndex, 0, item)\n }\n\n return nextLanguageIndex < 0\n ? // No next language (-1), add to end of array\n insert([item], 'after', [...path, nextLanguageIndex])\n : // Next language found, insert before that\n insert([item], 'before', [...path, nextLanguageIndex])\n })\n\n return insertions\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {TranslateIcon} from '@sanity/icons/Translate'\nimport {useCallback} from 'react'\nimport {\n defineDocumentFieldAction,\n type DocumentFieldActionItem,\n type DocumentFieldActionProps,\n PatchEvent,\n setIfMissing,\n useFormValue,\n} from 'sanity'\nimport {useDocumentPane} from 'sanity/structure'\n\nimport {useInternationalizedArrayContext} from '../components/InternationalizedArrayContext'\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {Language, InternationalizedArrayItem} from '../types'\nimport {checkAllLanguagesArePresent} from '../utils/checkAllLanguagesArePresent'\nimport {createAddAllTitle} from '../utils/createAddAllTitle'\nimport {createAddLanguagePatches} from '../utils/createAddLanguagePatches'\n\nconst createTranslateFieldActions: (\n fieldActionProps: DocumentFieldActionProps,\n context: {\n languages: Language[]\n filteredLanguages: Language[]\n },\n) => DocumentFieldActionItem[] = (fieldActionProps, {languages, filteredLanguages}) =>\n languages.map((language) => {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const value = useFormValue(fieldActionProps.path) as InternationalizedArrayItem[]\n const {onChange, formState} = useDocumentPane()\n const disabled =\n Boolean(formState?.readOnly) ||\n (value && Array.isArray(value)\n ? Boolean(value?.find((item) => item[LANGUAGE_FIELD_NAME] === language.id))\n : false)\n const hidden = !filteredLanguages.some((f) => f.id === language.id)\n\n const onAction = useCallback(() => {\n const {schemaType, path} = fieldActionProps\n\n const addLanguageKeys = [language.id]\n const patches = createAddLanguagePatches({\n addLanguageKeys,\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value,\n path,\n })\n\n onChange(PatchEvent.from([setIfMissing([], path), ...patches]))\n }, [language.id, value, onChange])\n\n return {\n type: 'action',\n icon: AddIcon,\n onAction,\n title: language.title,\n hidden,\n disabled,\n }\n })\n\nconst AddMissingTranslationsFieldAction: (\n fieldActionProps: DocumentFieldActionProps,\n context: {\n languages: Language[]\n filteredLanguages: Language[]\n },\n) => DocumentFieldActionItem = (fieldActionProps, {languages, filteredLanguages}) => {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const value = useFormValue(fieldActionProps.path) as InternationalizedArrayItem[]\n const {onChange, formState} = useDocumentPane()\n const disabled =\n Boolean(formState?.readOnly) || (value && value.length === filteredLanguages.length)\n const hidden = checkAllLanguagesArePresent(filteredLanguages, value)\n\n const onAction = useCallback(() => {\n const {schemaType, path} = fieldActionProps\n\n const addLanguageKeys: string[] = []\n const patches = createAddLanguagePatches({\n addLanguageKeys,\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value,\n path,\n })\n\n onChange(PatchEvent.from([setIfMissing([], path), ...patches]))\n }, [fieldActionProps, filteredLanguages, languages, onChange, value])\n\n return {\n type: 'action',\n icon: AddIcon,\n onAction,\n title: createAddAllTitle(value, filteredLanguages),\n disabled,\n hidden,\n }\n}\n\nexport const internationalizedArrayFieldAction = defineDocumentFieldAction({\n name: 'internationalizedArray',\n useAction(fieldActionProps) {\n const isInternationalizedArrayField =\n fieldActionProps?.schemaType?.type?.name.startsWith('internationalizedArray')\n const {languages, filteredLanguages} = useInternationalizedArrayContext()\n\n const translateFieldActions = createTranslateFieldActions(fieldActionProps, {\n languages,\n filteredLanguages,\n })\n\n return {\n type: 'group',\n icon: TranslateIcon,\n title: 'Add Translation',\n renderAsButton: true,\n children: isInternationalizedArrayField\n ? [\n ...translateFieldActions,\n AddMissingTranslationsFieldAction(fieldActionProps, {\n languages,\n filteredLanguages,\n }),\n ]\n : [],\n hidden: !isInternationalizedArrayField,\n }\n },\n})\n","import camelCase from 'lodash-es/camelCase.js'\nimport upperFirst from 'lodash-es/upperFirst.js'\n\n/**\n * Converts a string to PascalCase (e.g. `\"my-field\"` -> `\"MyField\"`).\n */\nexport function pascalCase(string: string): string {\n return upperFirst(camelCase(string))\n}\n\n/**\n * Generates the schema type name for an internationalized array field.\n *\n * - Without the value suffix: `\"internationalizedArray{PascalName}\"`\n * (used for the outer array type)\n * - With the value suffix: `\"internationalizedArray{PascalName}Value\"`\n * (used for the inner object type that wraps each language entry)\n *\n * For example, `createFieldName('block-content', true)` returns\n * `\"internationalizedArrayBlockContentValue\"`.\n */\nexport function createFieldName(name: string, addValue = false): string {\n return addValue\n ? [`internationalizedArray`, pascalCase(name), `Value`].join(``)\n : [`internationalizedArray`, pascalCase(name)].join(``)\n}\n","import type {ObjectSchemaType, FieldMember, FieldsetState} from 'sanity'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport {isInternationalizedArrayItemType, type Language} from '../types'\n\n/**\n * Default filter function for the internationalized array field.\n * It filter the field base on the `language` value of the object.\n */\nexport const internationalizedArrayLanguageFilter = (\n enclosingType: ObjectSchemaType,\n _member: FieldMember | FieldsetState,\n selectedLanguageIds: string[],\n parentValue: Record<string, unknown> | undefined,\n languages: Language[],\n) => {\n if (isInternationalizedArrayItemType(enclosingType.name)) {\n const language =\n typeof parentValue?.[LANGUAGE_FIELD_NAME] === 'string'\n ? parentValue?.[LANGUAGE_FIELD_NAME]\n : typeof parentValue?.['_key'] === 'string'\n ? parentValue?.['_key']\n : null\n\n const isAValidLanguage = language ? languages.find((l) => l.id === language) : true\n if (!isAValidLanguage) {\n // If it's not a valid language we should not hide it, because it needs to be surfaced to the user to fix it.\n // We need to update language-filter plugin so it doesn't hide the field later.\n return true\n }\n return language ? selectedLanguageIds.includes(language) : false\n }\n return true\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {TranslateIcon} from '@sanity/icons/Translate'\nimport {Button, Flex} from '@sanity/ui'\nimport {Menu, MenuButton, MenuDivider, MenuItem} from '@sanity/ui/menu'\nimport {useId} from 'react'\n\nimport {getLanguageDisplay} from '../utils/getLanguageDisplay'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\n\ntype CompactAddButtonProps = {\n readOnly: boolean\n handleClick: (languageId: string) => void\n languagesInUse: string[]\n onAddAll: () => void\n buttonAddAll: boolean\n addAllTitle: string\n allFilteredLanguagesArePresent: boolean\n}\n\n/**\n * One translate-icon button that opens a language menu — the `fieldMenu`\n * location. Compact, uses only stable `@sanity/ui`, and stays visible even\n * when every language is already present.\n */\nfunction CompactAddButton(props: CompactAddButtonProps) {\n const {\n readOnly,\n languagesInUse,\n handleClick,\n onAddAll,\n buttonAddAll,\n addAllTitle,\n allFilteredLanguagesArePresent,\n } = props\n const {languageDisplay, filteredLanguages: languages} = useInternationalizedArrayContext()\n const menuId = useId()\n\n if (!languages.length) return null\n\n return (\n <Flex justify=\"flex-end\" data-testid=\"field-menu\">\n <MenuButton\n id={menuId}\n popover={{portal: true, placement: 'bottom-end'}}\n button={\n <Button\n mode=\"bleed\"\n tone=\"default\"\n fontSize={1}\n padding={2}\n icon={TranslateIcon}\n aria-label=\"Add translation\"\n title=\"Add translation\"\n data-testid=\"add-translation-menu\"\n disabled={readOnly}\n />\n }\n menu={\n <Menu>\n {languages.map((language) => (\n <MenuItem\n key={language.id}\n text={getLanguageDisplay(languageDisplay, language.title, language.id)}\n icon={AddIcon}\n disabled={readOnly || languagesInUse.includes(language.id)}\n data-testid={`field-menu-add-${language.id}`}\n onClick={() => handleClick(language.id)}\n />\n ))}\n {buttonAddAll ? (\n <>\n <MenuDivider />\n <MenuItem\n text={addAllTitle}\n icon={TranslateIcon}\n disabled={readOnly || allFilteredLanguagesArePresent}\n data-testid=\"field-menu-add-all\"\n onClick={onAddAll}\n />\n </>\n ) : null}\n </Menu>\n }\n />\n </Flex>\n )\n}\n\nexport default CompactAddButton\n","import {Card, Stack, Text} from '@sanity/ui'\nimport {Code} from '@sanity/ui/code'\nimport type React from 'react'\n\nconst schemaExample = {\n languages: [\n {id: 'en', title: 'English'},\n {id: 'no', title: 'Norsk'},\n ],\n}\n\nexport default function Feedback(): React.ReactElement {\n return (\n <Card tone=\"caution\" border radius={2} padding={3}>\n <Stack gap={4}>\n <Text>\n An array of language objects must be passed into the <code>internationalizedArray</code>{' '}\n helper function, each with an <code>id</code> and <code>title</code> field. Example:\n </Text>\n <Card padding={2} border radius={2}>\n <Code size={1} language=\"javascript\">\n {JSON.stringify(schemaExample, null, 2)}\n </Code>\n </Card>\n </Stack>\n </Card>\n )\n}\n","import {WarningOutlineIcon} from '@sanity/icons/WarningOutline'\nimport {Box, Card, Flex, Stack, Text} from '@sanity/ui'\nimport {type ReactElement} from 'react'\n\nimport type {InternationalizedArrayItem} from '../types'\n\nexport type MigrationBannerProps = {\n itemsNeedingMigration: InternationalizedArrayItem[]\n}\n\n/**\n * Migration banner component that displays a warning if the items need to be migrated to the v5 format.\n */\nexport function MigrationBanner({\n itemsNeedingMigration,\n}: MigrationBannerProps): ReactElement | null {\n // Don't render if no migration is needed\n if (!itemsNeedingMigration.length) {\n return null\n }\n\n return (\n <Card tone=\"caution\" padding={3} radius={2} border>\n <Flex gap={3} align=\"center\">\n <Box>\n <Text size={1}>\n <WarningOutlineIcon />\n </Text>\n </Box>\n <Stack gap={2} flex={1}>\n <Text size={1} weight=\"semibold\">\n Data migration required\n </Text>\n <Text size={1} muted>\n {itemsNeedingMigration.length} item\n {itemsNeedingMigration.length === 1 ? '' : 's'}{' '}\n {itemsNeedingMigration.length === 1 ? 'needs' : 'need'} to be migrated to the v5 format.\n </Text>\n <Box marginTop={2}>\n <Text size={1}>\n This field still uses the v4 format where language is stored in <code>_key</code>.\n Migrate to the v5 format where language is stored in <code>language</code>.{' '}\n <a\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n href=\"https://github.com/sanity-io/plugins/blob/main/plugins/sanity-plugin-internationalized-array/README.md#migrate-from-v4-to-v5\"\n >\n Learn more\n </a>\n .\n </Text>\n </Box>\n </Stack>\n </Flex>\n </Card>\n )\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {useLanguageFilterStudioContext} from '@sanity/language-filter'\nimport {Button, Card, Stack, Text} from '@sanity/ui'\nimport {useToast} from '@sanity/ui/toast'\nimport type React from 'react'\nimport {useCallback, useContext, useEffect, useMemo} from 'react'\nimport {\n type ArrayOfObjectsInputProps,\n ArrayOfObjectsItem,\n MemberItemError,\n set,\n setIfMissing,\n useFormValue,\n useGetFormValue,\n} from 'sanity'\nimport {EventsContext} from 'sanity/_singletons'\nimport {useDocumentPane} from 'sanity/structure'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {InternationalizedArrayItem} from '../types'\nimport {createAddAllTitle} from '../utils/createAddAllTitle'\nimport {createAddLanguagePatches} from '../utils/createAddLanguagePatches'\nimport {internationalizedArrayLanguageFilter} from '../utils/internationalizedArrayLanguageFilter'\nimport AddButtons from './AddButtons'\nimport CompactAddButton from './CompactAddButton'\nimport Feedback from './Feedback'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\nimport {MigrationBanner} from './MigrationBanner'\n\n/**\n * The events store has finished loading and recorded no history. That is a\n * brand-new document.\n *\n * `sanity/_singletons` is internal; this is the same context `useEvents()`\n * reads. Using the context directly avoids throwing when the events API is\n * off (legacy timeline has no `EventsProvider`).\n */\nfunction isPristineDocument(\n events: {events: readonly unknown[]; loading: boolean} | null,\n): boolean {\n if (!events || events.loading) {\n return false\n }\n return events.events.length === 0\n}\n\n/**\n * Main array input component for internationalized array fields.\n *\n * Replaces the default Sanity array input and manages the full lifecycle of\n * language entries:\n *\n * - **Language filter integration**: When `@sanity/language-filter` is active\n * for the current document type, array members are filtered to only show\n * languages matching the user's selection.\n * - **Adding languages**: Exposes per-language buttons, an optional compact\n * `fieldMenu`, and an \"Add all / Add missing languages\" button (controlled\n * by `buttonAddAll` and `buttonLocations`). Dispatches `setIfMissing` +\n * `insert` patches.\n * - **Default languages**: Automatically adds entries for languages listed in\n * `defaultLanguages` when those entries are missing. Seeds brand-new\n * documents once the events store reports they are pristine (no history),\n * and seeds persisted documents that already have a `_rev`. A document\n * that existed and was deleted is not pristine, so opening it — even in a\n * fresh pane — does not recreate it. Newly created documents stay\n * read-only until initial value templates resolve, and the field-level\n * `readOnly` prop can lag that document-level lock. Skipping the patch\n * until writable avoids \"Attempted to patch a read-only document\" toasts.\n * - **Ordering**: When `restoreOrder` is enabled (default), detects when value\n * items are out of order relative to the master `languages` list and\n * automatically re-sorts them. Set `restoreOrder: false` to keep the stored\n * order and avoid silent draft creation on open.\n * - **Validation**: Shows a `<Feedback>` component if the languages\n * configuration is invalid (e.g. missing `id` or `title`).\n * - **Empty state**: Displays a \"no translations\" message when the field has\n * no entries and the add buttons are not visible.\n */\nexport default function InternationalizedArray(\n props: ArrayOfObjectsInputProps,\n): React.ReactElement {\n const {members, value: _value, schemaType, onChange, readOnly: documentReadOnly} = props\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n const value = _value as InternationalizedArrayItem[]\n const itemsNeedingMigration = value?.filter((v) => !v[LANGUAGE_FIELD_NAME]) ?? []\n const shouldMigrateArray = itemsNeedingMigration.length > 0\n const toast = useToast()\n\n const getFormValue = useGetFormValue()\n const {\n languages,\n filteredLanguages,\n defaultLanguages,\n buttonAddAll,\n buttonLocations,\n restoreOrder,\n languageFilter: builtInLanguageFilter,\n } = useInternationalizedArrayContext()\n // Support updating the UI if languageFilter is installed\n const {selectedLanguageIds, options: languageFilterOptions} = useLanguageFilterStudioContext()\n const documentType = useFormValue(['_type'])\n const usingLanguageFilterPlugin =\n typeof documentType === 'string' && languageFilterOptions.documentTypes.includes(documentType)\n const usingBuiltInLanguageFilter =\n typeof documentType === 'string' && builtInLanguageFilter.documentTypes.includes(documentType)\n\n // TODO: Is this redundant? The filter plugin already filters members at its own level.\n const filteredMembers = useMemo(\n () =>\n usingLanguageFilterPlugin || usingBuiltInLanguageFilter\n ? members.filter((member) => {\n // This member is the outer object created by the plugin\n // Satisfy TS\n if (member.kind !== 'item') {\n return false\n }\n\n // This is the inner \"value\" field member created by this plugin\n const valueMember = member.item.members[0]\n\n // Satisfy TS\n if (!valueMember || valueMember.kind !== 'field') {\n return false\n }\n // The built-in filter receives the full languages list so it can\n // surface fields with invalid language IDs rather than hiding them.\n // The language filter plugin does not support this.\n return usingBuiltInLanguageFilter\n ? internationalizedArrayLanguageFilter(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n languages,\n )\n : languageFilterOptions.filterField(\n member.item.schemaType,\n valueMember,\n selectedLanguageIds,\n member.item.value,\n )\n })\n : members,\n [\n usingLanguageFilterPlugin,\n usingBuiltInLanguageFilter,\n members,\n selectedLanguageIds,\n languages,\n languageFilterOptions,\n ],\n )\n\n const {isDeleted, isDeleting, isInitialValueLoading, formState} = useDocumentPane()\n\n // Document-level locks (initial-value templates, permissions, history) are\n // not always reflected on the field's `readOnly` prop in the same tick as\n // the patch channel. Gating on both prevents toasts from auto-patches.\n const readOnly =\n Boolean(documentReadOnly) ||\n schemaType.readOnly === true ||\n Boolean(formState?.readOnly) ||\n Boolean(isInitialValueLoading)\n\n const handleAddLanguages = useCallback(\n (addLanguageKeys: string[] | string) => {\n if (readOnly) {\n return\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion\n const formValue = getFormValue(props.path) as InternationalizedArrayItem[]\n if (!filteredLanguages?.length) {\n return\n }\n\n const patches = createAddLanguagePatches({\n addLanguageKeys: Array.isArray(addLanguageKeys) ? addLanguageKeys : [addLanguageKeys],\n schemaTypeName: schemaType.name,\n languages,\n filteredLanguages,\n value: formValue,\n })\n\n onChange([setIfMissing([]), ...patches])\n },\n [filteredLanguages, languages, onChange, schemaType, getFormValue, props.path, readOnly],\n )\n\n // `_rev` means the document is in the dataset. No `_rev` is either a\n // brand-new form or a deleted one. The events store distinguishes those:\n // pristine (loaded, zero events) has never existed; any history means it\n // did — including a fresh open of a deleted id, where this pane never saw\n // a `_rev`.\n const documentExists = Boolean(useFormValue(['_rev']))\n const isPristine = isPristineDocument(useContext(EventsContext))\n\n // Create a stable dependency string that only changes when language keys change\n const languageKeysFromValue = value\n ?.map((v) => v[LANGUAGE_FIELD_NAME] ?? v._key)\n .filter(Boolean)\n .join(',')\n\n const addedLanguages = useMemo(() => {\n const languageKeys = languageKeysFromValue?.split(',') || []\n if (!languageKeys?.length) return []\n if (!languages?.length) return []\n\n return languages.filter((l) => languageKeys?.find((key) => key === l.id)).map((l) => l.id)\n }, [languageKeysFromValue, languages])\n\n useEffect(() => {\n const hasAddedDefaultLanguages = defaultLanguages\n .filter((language) => languages.find((l) => l.id === language))\n .every((language) => addedLanguages.includes(language))\n\n if (\n (isPristine || documentExists) &&\n !isDeleting &&\n !isDeleted &&\n !hasAddedDefaultLanguages &&\n !shouldMigrateArray &&\n !readOnly\n ) {\n const languagesToAdd = defaultLanguages\n .filter((language) => !addedLanguages.includes(language))\n .filter((language) => languages.find((l) => l.id === language))\n // Account for strict mode by scheduling the update.\n const timeout = setTimeout(() => {\n if (!readOnly) handleAddLanguages(languagesToAdd)\n })\n return () => clearTimeout(timeout)\n }\n return undefined\n }, [\n isPristine,\n documentExists,\n isDeleted,\n isDeleting,\n handleAddLanguages,\n defaultLanguages,\n addedLanguages,\n languages,\n readOnly,\n shouldMigrateArray,\n ])\n\n // NOTE: This is reordering and re-setting the whole array, it could be surgical\n const handleRestoreOrder = useCallback(() => {\n if (readOnly || !value?.length || !languages?.length) {\n return\n }\n\n // Create a new value array in the correct order\n // This would also strip out values that don't have a language as the key\n const updatedValue = value\n .reduce((acc, v) => {\n const newIndex = languages.findIndex((l) => l.id === v?.[LANGUAGE_FIELD_NAME])\n\n if (newIndex > -1) {\n acc[newIndex] = v\n }\n\n return acc\n }, [] as InternationalizedArrayItem[])\n .filter(Boolean)\n\n if (value?.length !== updatedValue.length) {\n toast.push({\n title: 'There was an error reordering languages',\n status: 'warning',\n })\n }\n\n onChange(set(updatedValue))\n }, [toast, languages, onChange, value, readOnly])\n\n const allKeysAreLanguages = useMemo(() => {\n if (!value?.length || !languages?.length) {\n return true\n }\n\n return value?.every((v) => languages.find((l) => l?.id === v?.[LANGUAGE_FIELD_NAME]))\n }, [value, languages])\n\n const languagesOutOfOrder = useMemo(() => {\n if (!value?.length || !addedLanguages.length) {\n return []\n }\n\n return value\n .map((v, vIndex) =>\n vIndex === addedLanguages.findIndex((language) => language === v[LANGUAGE_FIELD_NAME])\n ? null\n : v,\n )\n .filter(Boolean)\n }, [value, addedLanguages])\n\n const languagesAreValid = useMemo(\n () =>\n !languages?.length || (languages?.length && languages.every((item) => item.id && item.title)),\n [languages],\n )\n\n // Automatically restore order of fields (opt out with restoreOrder: false)\n useEffect(() => {\n if (restoreOrder && languagesOutOfOrder.length > 0 && allKeysAreLanguages && !readOnly) {\n handleRestoreOrder()\n }\n }, [restoreOrder, languagesOutOfOrder, allKeysAreLanguages, handleRestoreOrder, readOnly])\n\n const allFilteredLanguagesArePresent = useMemo(\n () => filteredLanguages.every((language) => addedLanguages.includes(language.id)),\n [filteredLanguages, addedLanguages],\n )\n const addAllMissingLanguages = useCallback(() => {\n handleAddLanguages(filteredLanguages.map((language) => language.id))\n }, [filteredLanguages, handleAddLanguages])\n\n if (!languagesAreValid) {\n return <Feedback />\n }\n\n const canAddLanguages = !shouldMigrateArray && filteredLanguages?.length > 0\n const showFieldMenu = canAddLanguages && buttonLocations.includes('fieldMenu')\n const showFieldButtons =\n canAddLanguages && buttonLocations.includes('field') && !allFilteredLanguagesArePresent\n const fieldHasMembers = members?.length > 0\n const addAllTitle = createAddAllTitle(value, filteredLanguages)\n\n const fieldButtons = showFieldButtons ? (\n <Stack gap={2}>\n <AddButtons\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n />\n {buttonAddAll ? (\n <Button\n tone=\"primary\"\n mode=\"ghost\"\n data-testid=\"add-all-languages\"\n disabled={readOnly || allFilteredLanguagesArePresent}\n icon={AddIcon}\n text={addAllTitle}\n onClick={addAllMissingLanguages}\n />\n ) : null}\n </Stack>\n ) : null\n\n return (\n <Stack gap={2}>\n {showFieldMenu ? (\n <CompactAddButton\n languagesInUse={addedLanguages}\n readOnly={readOnly}\n handleClick={handleAddLanguages}\n onAddAll={addAllMissingLanguages}\n buttonAddAll={buttonAddAll}\n addAllTitle={addAllTitle}\n allFilteredLanguagesArePresent={allFilteredLanguagesArePresent}\n />\n ) : null}\n {filteredMembers.map((member) => {\n if (member.kind === 'item') {\n return <ArrayOfObjectsItem {...props} key={member.key} member={member} />\n }\n return <MemberItemError key={member.key} member={member} />\n })}\n <MigrationBanner itemsNeedingMigration={itemsNeedingMigration} />\n\n {/* Give some feedback in the UI so the field doesn't look \"missing\" */}\n {!showFieldMenu && !showFieldButtons && !fieldHasMembers ? (\n <Card border tone=\"transparent\" padding={3} radius={2}>\n <Text size={1}>This internationalized field currently has no translations.</Text>\n </Card>\n ) : null}\n\n {fieldButtons}\n </Stack>\n )\n}\n","import type {SchemaType} from 'sanity'\n\nimport type {ArrayFieldOptions} from '../schema/array'\n\nexport function getLanguagesFieldOption(\n schemaType: SchemaType | undefined,\n): ArrayFieldOptions['languages'] | undefined {\n if (!schemaType) {\n return undefined\n }\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const languagesOption = (schemaType.options as ArrayFieldOptions)?.languages\n if (languagesOption) {\n return languagesOption\n }\n return getLanguagesFieldOption(schemaType.type)\n}\n","import {defineField, type FieldDefinition, type FieldProps, type Rule} from 'sanity'\n\nimport {getFunctionCache, peek, setFunctionCache} from '../cache'\nimport {createFieldName} from '../components/createFieldName'\nimport {getSelectedValue} from '../components/getSelectedValue'\nimport InternationalizedArray from '../components/InternationalizedArray'\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {Language, LanguageCallback, InternationalizedArrayItem} from '../types'\nimport {getLanguagesFieldOption} from '../utils/getLanguagesFieldOption'\n\ntype ArrayFactoryConfig = {\n apiVersion: string\n select?: Record<string, string>\n languages: Language[] | LanguageCallback\n defaultLanguages?: string[]\n type: string | FieldDefinition\n}\n\nexport type ArrayFieldOptions = Pick<ArrayFactoryConfig, 'apiVersion' | 'select' | 'languages'>\n\nexport default (config: ArrayFactoryConfig) => {\n const {apiVersion, select, languages, type} = config\n const typeName = typeof type === `string` ? type : type.name\n const arrayName = createFieldName(typeName)\n const objectName = createFieldName(typeName, true)\n\n return defineField({\n name: arrayName,\n title: 'Internationalized array',\n type: 'array',\n components: {\n field: (props: FieldProps) =>\n props.renderDefault({\n ...props,\n // Reset the level to avoid nested styling\n level: 0,\n }),\n input: InternationalizedArray,\n },\n options: {\n // @ts-expect-error - these options are required for validation rules – not the custom input component\n apiVersion,\n select,\n languages,\n },\n of: [\n defineField({\n ...(typeof type === 'string' ? {} : type),\n name: objectName,\n type: objectName,\n }),\n ],\n // @ts-expect-error - fix typings\n validation: (rule: Rule) =>\n rule.custom<InternationalizedArrayItem[]>(async (value, context) => {\n if (!value || value.length === 0) {\n return true\n }\n\n // Check for items missing the language field (unmigrated data)\n const itemsMissingLanguage = value.filter(\n (item) => item && !item[LANGUAGE_FIELD_NAME] && item._key,\n )\n if (itemsMissingLanguage.length > 0) {\n return {\n message:\n 'Language is required for each array item. Run the migration to update your data from the old format.',\n paths: itemsMissingLanguage.flatMap((item) => [\n [{_key: item._key}],\n [{_key: item._key}, 'value'],\n ]),\n }\n }\n\n // Early return for simple cases to avoid expensive operations\n if (value.length === 1 && !value[0]?.[LANGUAGE_FIELD_NAME]) {\n return true\n }\n\n const selectedValue = getSelectedValue(select, context.document)\n const client = context.getClient({apiVersion})\n\n let contextLanguages: Language[] = []\n const languagesFieldOption = getLanguagesFieldOption(context?.type)\n\n if (Array.isArray(languagesFieldOption)) {\n contextLanguages = languagesFieldOption\n } else if (Array.isArray(peek(selectedValue))) {\n contextLanguages = peek(selectedValue) || []\n } else if (typeof languagesFieldOption === 'function') {\n // Try to get from function cache first (if it's the same function as the component)\n const cachedLanguages = getFunctionCache(languagesFieldOption, selectedValue)\n\n if (Array.isArray(cachedLanguages)) {\n contextLanguages = cachedLanguages\n } else {\n // Try suspend cache as fallback\n const suspendCachedLanguages = peek(selectedValue)\n if (Array.isArray(suspendCachedLanguages)) {\n contextLanguages = suspendCachedLanguages\n } else {\n // Only make the async call if we don't have cached data\n contextLanguages = await languagesFieldOption(client, selectedValue)\n // Cache the result for future validation calls\n setFunctionCache(languagesFieldOption, selectedValue, contextLanguages)\n }\n }\n }\n\n if (value && value.length > contextLanguages.length) {\n return `Cannot be more than ${\n contextLanguages.length === 1 ? `1 item` : `${contextLanguages.length} items`\n }`\n }\n\n // Create a Set for faster language ID lookups\n const languageIds = new Set(contextLanguages.map((lang) => lang.id))\n\n // Check for invalid language keys\n const nonLanguageKeys = value.filter(\n (item) => item?.[LANGUAGE_FIELD_NAME] && !languageIds.has(item[LANGUAGE_FIELD_NAME]),\n )\n if (nonLanguageKeys.length) {\n return {\n message: `Array item keys must be valid languages registered to the field type`,\n paths: nonLanguageKeys.map((item) => [{_key: item._key}]),\n }\n }\n\n // Check for duplicate language keys (more efficient)\n const seenLanguages = new Set<string>()\n const duplicateValues: InternationalizedArrayItem[] = []\n\n for (const item of value) {\n if (item?.[LANGUAGE_FIELD_NAME]) {\n if (seenLanguages.has(item[LANGUAGE_FIELD_NAME])) {\n duplicateValues.push(item)\n } else {\n seenLanguages.add(item[LANGUAGE_FIELD_NAME])\n }\n }\n }\n\n if (duplicateValues.length) {\n return {\n message: 'There can only be one field per language',\n paths: duplicateValues.map((item) => [{_key: item._key}]),\n }\n }\n\n return true\n }),\n })\n}\n","import type {CardTone} from '@sanity/ui'\nimport type {FormNodeValidation} from 'sanity'\n\n/**\n * Maps an array of Sanity form validation entries to a `@sanity/ui` `CardTone`\n * for visual feedback on internationalized array items.\n *\n * - Returns `'critical'` if any validation has `level: 'error'`\n * - Returns `'caution'` if any validation has `level: 'warning'` (and no errors)\n * - Returns `undefined` otherwise (no tone applied)\n *\n * Error level always takes precedence over warning.\n */\nexport function getToneFromValidation(validations: FormNodeValidation[]): CardTone | undefined {\n if (!validations?.length) {\n return undefined\n }\n\n const validationLevels = new Set(validations.map((v) => v.level))\n\n if (validationLevels.has('error')) {\n return `critical`\n } else if (validationLevels.has('warning')) {\n return `caution`\n }\n\n return undefined\n}\n","import {RemoveCircleIcon} from '@sanity/icons/RemoveCircle'\nimport {Box, Button, Card, Flex, Label, Spinner, Text} from '@sanity/ui'\nimport {Menu, MenuButton, MenuItem} from '@sanity/ui/menu'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport type React from 'react'\nimport {type ReactNode, useCallback, useMemo} from 'react'\nimport {type FormPatch, type ObjectItemProps, PatchEvent, type Path, useFormValue} from 'sanity'\nimport {set, unset} from 'sanity'\n\nimport {LANGUAGE_FIELD_NAME} from '../constants'\nimport type {InternationalizedArrayItem} from '../types'\nimport {getLanguageDisplay} from '../utils/getLanguageDisplay'\nimport {getToneFromValidation} from './getToneFromValidation'\nimport {useInternationalizedArrayContext} from './InternationalizedArrayContext'\n\nfunction ChangeLanguageButton(props: {\n value: InternationalizedArrayItem\n path: Path\n onChange: (patch: FormPatch[] | PatchEvent | FormPatch) => void\n}): ReactNode {\n const {value, onChange, path} = props\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n const parentValue = useFormValue(path.slice(0, -1)) as InternationalizedArrayItem[]\n const {languages} = useInternationalizedArrayContext()\n\n const languageKeysInUse = useMemo(\n () => parentValue?.map((v) => v[LANGUAGE_FIELD_NAME]) ?? [],\n [parentValue],\n )\n\n // Changes the key of this item, ideally to a valid language\n const handleKeyChange = (event: React.MouseEvent<HTMLButtonElement>): void => {\n const languageId = event?.currentTarget?.value\n\n if (!value || !languages?.length || !languages.find((l) => l.id === languageId)) {\n return\n }\n\n onChange([set(languageId, [LANGUAGE_FIELD_NAME])])\n }\n\n return (\n <MenuButton\n button={<Button fontSize={1} text={`Change \"${value[LANGUAGE_FIELD_NAME]}\"`} />}\n id={`${value[LANGUAGE_FIELD_NAME]}-change-key`}\n menu={\n <Menu>\n {languages.map((lang) => (\n <MenuItem\n disabled={languageKeysInUse.includes(lang.id)}\n fontSize={1}\n key={lang.id}\n text={lang.id.toLocaleUpperCase()}\n value={lang.id}\n onClick={handleKeyChange}\n />\n ))}\n </Menu>\n }\n popover={{portal: true}}\n />\n )\n}\n\nfunction RemoveButton({\n isDefault,\n readOnly,\n onChange,\n}: {\n isDefault: boolean\n readOnly: boolean\n onChange: (patch: FormPatch[] | PatchEvent | FormPatch) => void\n}): ReactNode {\n // Removes this item from the array\n const handleUnset = (): void => {\n onChange(unset())\n }\n\n return (\n <Tooltip\n animate\n disabled={!isDefault}\n content={\n <Text muted size={1}>\n Can't remove default language\n </Text>\n }\n fallbackPlacements={['right', 'left']}\n placement=\"top\"\n portal\n >\n <span style={{paddingBottom: '2px'}}>\n <Button\n mode=\"bleed\"\n icon={RemoveCircleIcon}\n tone=\"critical\"\n disabled={readOnly || isDefault}\n onClick={handleUnset}\n />\n </span>\n </Tooltip>\n )\n}\n\n/**\n * Renders a single row of an internationalized array: a language label (or\n * \"Change\" menu for invalid keys), the value input, and a remove button.\n *\n * Key behaviours:\n * - Wraps `onChange` to intercept paste operations into empty Portable Text\n * fields, ensuring `setIfMissing` and correct path prefixing.\n * - Detects items needing migration (missing `LANGUAGE_FIELD_NAME`) and hides\n * the language label in that state.\n * - Shows a `MenuButton` with available languages when the current key is\n * not a valid language.\n * - Disables the remove button for languages listed in `defaultLanguages`.\n * - Shows a `Spinner` when languages have not been loaded yet.\n * - Applies a `CardTone` based on validation state via `getToneFromValidation`.\n */\nexport default function InternationalizedInput(\n props: ObjectItemProps<InternationalizedArrayItem>,\n): ReactNode {\n // Extract the original onChange to avoid dependency issues\n const originalOnChange = props.inputProps.onChange\n\n // Create a wrapped onChange handler to intercept patches for paste operations\n const wrappedOnChange = useCallback(\n (patches: unknown) => {\n // Ensure patches is an array before proceeding with paste logic\n // For single patch operations (like unset), pass through directly\n if (!Array.isArray(patches)) {\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n }\n\n // Check if this is a paste operation into an empty or uninitialized Portable Text field\n const valueField = props.value?.value\n const isEmptyOrUndefined =\n valueField === undefined ||\n valueField === null ||\n (Array.isArray(valueField) && valueField.length === 0)\n\n if (isEmptyOrUndefined) {\n // Check for insert patches that are trying to operate on a non-existent structure\n const hasProblematicInsert = patches.some((patch: {type?: string; path?: unknown[]}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return false\n }\n\n // Look for insert patches targeting the value field or direct array index\n if (\n patch.type === 'insert' &&\n patch.path &&\n Array.isArray(patch.path) &&\n patch.path.length > 0\n ) {\n // The path might be ['value', index] or just [index] depending on context\n const isTargetingValue = patch.path[0] === 'value' || typeof patch.path[0] === 'number'\n return isTargetingValue\n }\n return false\n })\n\n if (hasProblematicInsert) {\n // First, ensure the value field exists as an empty array if it doesn't\n const initPatch =\n valueField === undefined ? {type: 'setIfMissing', path: ['value'], value: []} : null\n\n // Transform the patches to ensure they work with the nested structure\n const fixedPatches = patches.map(\n (patch: {type?: string; path?: unknown[]; [key: string]: unknown}) => {\n // Ensure patch exists and has required properties\n if (!patch || typeof patch !== 'object') {\n return patch\n }\n\n if (patch.type === 'insert' && patch.path && Array.isArray(patch.path)) {\n // Ensure the path is correct for the nested structure\n const fixedPath = patch.path[0] === 'value' ? patch.path : ['value', ...patch.path]\n const fixedPatch = {...patch, path: fixedPath}\n return fixedPatch\n }\n return patch\n },\n )\n\n // If we need to initialize the field, include that patch first\n const allPatches = initPatch ? [initPatch, ...fixedPatches] : fixedPatches\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion\n return originalOnChange(allPatches as Parameters<typeof originalOnChange>[0])\n }\n }\n\n // For all other cases, pass through unchanged\n return originalOnChange(patches as Parameters<typeof originalOnChange>[0])\n },\n [originalOnChange, props.value?.value],\n )\n\n // The parent array contains the languages from the plugin config\n const {languages, languageDisplay, defaultLanguages} = useInternationalizedArrayContext()\n\n const keyIsValid = languages?.length\n ? Boolean(languages.find((l) => l.id === props.value[LANGUAGE_FIELD_NAME]))\n : false\n\n const language = languages?.find((l) => l.id === props.value[LANGUAGE_FIELD_NAME])\n const languageTitle: string =\n keyIsValid && language ? getLanguageDisplay(languageDisplay, language.title, language.id) : ''\n\n const inlineProps = useMemo(\n () => ({\n ...props.inputProps,\n members: props.inputProps.members\n .filter((m) => m.kind === 'field' && m.name === 'value')\n .map((member) => {\n if (member.kind !== 'field') {\n return member\n }\n\n const field = member.field\n const schemaType = field?.schemaType\n const itemNeedsMigration = !props.value[LANGUAGE_FIELD_NAME]\n\n const title = itemNeedsMigration ? null : keyIsValid ? (\n <Label muted size={1}>\n {languageTitle}\n </Label>\n ) : (\n <ChangeLanguageButton\n value={props.value}\n path={props.path}\n onChange={originalOnChange}\n />\n )\n\n return Object.assign({}, member, {\n field: Object.assign({}, field, {\n schemaType: Object.assign({}, schemaType, {title}),\n }),\n })\n }),\n value: props.value,\n // Use our wrapped onChange handler\n onChange: wrappedOnChange,\n }),\n [\n props.inputProps,\n props.value,\n wrappedOnChange,\n languageTitle,\n keyIsValid,\n originalOnChange,\n props.path,\n ],\n )\n\n const {validation, value, readOnly} = inlineProps\n\n if (!languages) {\n return <Spinner />\n }\n\n const isDefault = defaultLanguages.includes(value[LANGUAGE_FIELD_NAME])\n\n return (\n <Card paddingTop={2} tone={getToneFromValidation(validation)}>\n <Flex align=\"flex-end\" gap={2}>\n <Box flex={1}>{props.inputProps.renderInput(inlineProps)}</Box>\n <RemoveButton\n isDefault={isDefault}\n readOnly={Boolean(readOnly)}\n onChange={originalOnChange}\n />\n </Flex>\n </Card>\n )\n}\n","import {defineField, type FieldDefinition, type FieldProps} from 'sanity'\n\nimport {createFieldName} from '../components/createFieldName'\nimport InternationalizedInput from '../components/InternationalizedInput'\nimport {LANGUAGE_FIELD_NAME} from '../constants'\n\ntype ObjectFactoryConfig = {\n type: string | FieldDefinition\n}\n\nexport default (config: ObjectFactoryConfig) => {\n const {type} = config\n const typeName = typeof type === `string` ? type : type.name\n const objectName = createFieldName(typeName, true)\n\n return defineField({\n name: objectName,\n title: `Internationalized array ${typeName}`,\n type: 'object',\n components: {\n // @ts-expect-error - fix typings\n item: InternationalizedInput,\n field: (props: FieldProps) =>\n props.renderDefault({\n ...props,\n // Reset the level to avoid nested styling\n level: 0,\n }),\n },\n fields: [\n defineField({\n ...(typeof type === 'string' ? {type} : type),\n name: 'value',\n }),\n // Hidden language field - stores the language identifier (e.g., 'en', 'fr')\n // This replaces the previous pattern of storing language in _key\n defineField({\n name: 'language',\n type: 'string',\n hidden: true,\n validation: (Rule) => Rule.required(),\n }),\n ],\n preview: {\n select: {\n title: 'value',\n subtitle: LANGUAGE_FIELD_NAME,\n },\n },\n })\n}\n","import {languageFilter} from '@sanity/language-filter'\nimport {definePlugin, isObjectInputProps} from 'sanity'\n\nimport {InternationalizedArrayFormInput} from './components/InternationalizedArrayFormInput'\nimport {InternationalizedArrayLayout} from './components/InternationalizedArrayLayout'\nimport Preload from './components/Preload'\nimport {CONFIG_DEFAULT} from './constants'\nimport {internationalizedArrayFieldAction} from './fieldActions'\nimport array from './schema/array'\nimport object from './schema/object'\nimport type {PluginConfig} from './types'\nimport {hasInternationalizedArrayField} from './utils/hasInternationalizedArrayField'\n\nexport const internationalizedArray = definePlugin<PluginConfig>((config) => {\n const pluginConfig = {...CONFIG_DEFAULT, ...config}\n const {\n // oxlint-disable-next-line no-useless-default-assignment\n apiVersion = '2025-10-15',\n select,\n languages,\n fieldTypes,\n defaultLanguages,\n buttonLocations,\n languageFilter: languageFilterConfig,\n } = pluginConfig\n\n return {\n name: 'sanity-plugin-internationalized-array',\n // Preload languages for use throughout the Studio\n studio: Array.isArray(languages)\n ? undefined\n : {\n components: {\n layout: (props) => (\n <>\n <Preload apiVersion={apiVersion} languages={languages} />\n {props.renderDefault(props)}\n </>\n ),\n },\n },\n // Optional: render \"add language\" buttons as field actions\n document: {\n components: {\n unstable_layout: (props) => (\n <InternationalizedArrayLayout {...props} pluginConfig={pluginConfig} />\n ),\n },\n unstable_fieldActions: buttonLocations.includes('unstable__fieldAction')\n ? (prev) => [...prev, internationalizedArrayFieldAction]\n : undefined,\n },\n // Wrap document editor with a language provider\n form: {\n components: {\n input: (props) => {\n const isRootInput = props.id === 'root' && isObjectInputProps(props)\n\n if (!isRootInput) {\n return props.renderDefault(props)\n }\n\n const hasInternationalizedArray = hasInternationalizedArrayField(props.schemaType)\n\n if (\n hasInternationalizedArray &&\n pluginConfig.includeForDocumentType(props.schemaType.name)\n ) {\n return <InternationalizedArrayFormInput {...props} pluginConfig={pluginConfig} />\n }\n return props.renderDefault(props)\n },\n },\n },\n // Register custom schema types for the outer array and the inner object\n schema: {\n types: [\n ...fieldTypes.map((type) => array({type, apiVersion, select, languages, defaultLanguages})),\n ...fieldTypes.map((type) => object({type})),\n ],\n },\n plugins:\n languageFilterConfig?.documentTypes?.length > 0\n ? [\n languageFilter({\n documentTypes: languageFilterConfig.documentTypes,\n supportedLanguages: languages,\n defaultLanguages: languageFilterConfig.defaultLanguages,\n // This is specifically not adding filterField avoid the default filter field implementation.\n // It will be filtered in `internationalizedArray` component and will have access to the resolved languages.\n // Rendering the fields if the language key is incorrect, providing an improved UX\n }),\n ]\n : undefined,\n }\n})\n"],"mappings":"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"}
\ No newline at end of file