From 06d812c001d2ec15d31d0e36b738123a773260e8 Mon Sep 17 00:00:00 2001 From: Tommy Petty Date: Tue, 19 Mar 2024 11:54:08 -0400 Subject: [PATCH] feat(tasks): Localize Task feature (#6017) * feat(tasks): Localize Task feature * feat(tasks): updated i18n keys to not have tasks prefix * feat(tasks): updated missing string to be localized * feat(task): i18n updates after rebase * feat(task): added i18n attribute exception --- .eslintrc.cjs | 11 +- packages/sanity/src/tasks/i18n/index.ts | 27 +++++ packages/sanity/src/tasks/i18n/resources.ts | 105 ++++++++++++++++++ packages/sanity/src/tasks/index.ts | 1 + .../src/tasks/plugin/TaskCreateAction.tsx | 9 +- .../src/tasks/plugin/TasksFooterOpenTasks.tsx | 17 ++- .../src/tasks/plugin/TasksStudioNavbar.tsx | 11 +- packages/sanity/src/tasks/plugin/index.tsx | 5 +- .../activity/TasksActivityCommentInput.tsx | 5 +- .../activity/TasksActivityCreatedAt.tsx | 9 +- .../components/activity/TasksActivityLog.tsx | 5 +- .../form/CurrentWorkspaceProvider.tsx | 1 + .../components/form/RemoveTaskDialog.tsx | 13 ++- .../form/fields/DateEditFormField.tsx | 9 +- .../form/fields/DescriptionInput.tsx | 12 +- .../components/form/fields/TargetField.tsx | 12 +- .../assignee/AssigneeCreateFormField.tsx | 13 ++- .../fields/assignee/AssigneeEditFormField.tsx | 13 ++- .../fields/assignee/AssigneeSelectionMenu.tsx | 13 ++- .../form/tasksFormBuilder/FormCreate.tsx | 17 +-- .../form/tasksFormBuilder/FormEdit.tsx | 21 +++- .../src/tasks/components/list/TasksList.tsx | 5 +- .../sidebar/TasksActiveTabNavigation.tsx | 10 +- .../sidebar/TasksHeaderDraftsMenu.tsx | 9 +- .../components/sidebar/TasksSidebarHeader.tsx | 22 +++- 25 files changed, 292 insertions(+), 83 deletions(-) create mode 100644 packages/sanity/src/tasks/i18n/index.ts create mode 100644 packages/sanity/src/tasks/i18n/resources.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index f4a820ad43e..2d5894934da 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -76,12 +76,14 @@ const config = { attributes: [ 'animate', 'closed', + 'documentType', 'exit', 'fill', 'full', 'initial', 'size', 'sortOrder', + 'status', 'group', ], }, @@ -280,15 +282,6 @@ const config = { '@sanity/i18n/no-attribute-template-literals': 'off', }, }, - // Ignore i18n in Tasks files for now. This will need to be removed before task is completed. - { - files: ['**/*/Tasks*.{js,ts,tsx}', '**/*/tasks/**/*'], - rules: { - 'i18next/no-literal-string': 'off', - '@sanity/i18n/no-attribute-string-literals': 'off', - '@sanity/i18n/no-attribute-template-literals': 'off', - }, - }, // Prefer local components vs certain @sanity/ui imports (in sanity package) { diff --git a/packages/sanity/src/tasks/i18n/index.ts b/packages/sanity/src/tasks/i18n/index.ts new file mode 100644 index 00000000000..102040e44be --- /dev/null +++ b/packages/sanity/src/tasks/i18n/index.ts @@ -0,0 +1,27 @@ +import {defineLocaleResourceBundle} from 'sanity' + +/** + * The locale namespace for the task tool + * + * @public + */ +export const tasksLocaleNamespace = 'tasks' as const + +/** + * The default locale bundle for the task tool, which is US English. + * + * @internal + */ +export const tasksUsEnglishLocaleBundle = defineLocaleResourceBundle({ + locale: 'en-US', + namespace: tasksLocaleNamespace, + resources: () => import('./resources'), +}) + +/** + * The locale resource keys for the task tool. + * + * @alpha + * @hidden + */ +export type {TasksLocaleResourceKeys} from './resources' diff --git a/packages/sanity/src/tasks/i18n/resources.ts b/packages/sanity/src/tasks/i18n/resources.ts new file mode 100644 index 00000000000..4093e41f8a5 --- /dev/null +++ b/packages/sanity/src/tasks/i18n/resources.ts @@ -0,0 +1,105 @@ +/* eslint sort-keys: "error" */ +import {defineLocalesResources} from 'sanity' + +/** + * Defined locale strings for the task tool, in US English. + * + * @internal + */ +const tasksLocaleStrings = defineLocalesResources('tasks', { + /** The label for the create task action */ + 'actions.create.text': 'Create new task', + /** The label for the open tasks panel action */ + 'actions.open.text': 'Tasks', + /** The label for the button to create a new task */ + 'buttons.create.text': 'Create Task', + /** The label for the button to discard changes */ + 'buttons.discard.text': 'Discard', + /** The label for the button to open the draft */ + 'buttons.draft.text': 'Draft', + /** The label for the button to create a new task */ + 'buttons.new.text': 'New task', + /** The label for the button that will navigate to the next task */ + 'buttons.next.tooltip': 'Go to next task', + /** The label for the button that will previous to the next task */ + 'buttons.previous.tooltip': 'Go to previous task', + /** Text for the remove task dialog asking for confirmation of deletion */ + 'dialog.remove-task.body': 'Are you sure you want to delete this task?', + /** Text for the remove task dialog clarifying that deletion is permanent */ + 'dialog.remove-task.body2': 'Once deleted, it cannot be restored.', + /** The label for the cancel button on the remove task dialog */ + 'dialog.remove-task.buttons.cancel.text': 'Cancel', + /** The label for the confirmation button on the remove task dialog */ + 'dialog.remove-task.buttons.confirm.text': 'Remove', + /** The title for the remove task dialog */ + 'dialog.remove-task.title': 'Remove task', + /** The text used as a placeholder for the footer action in a document with a single task */ + 'document.footer.open-tasks.placeholder_one': 'Open task', + /** The text used as a placeholder for the footer action in a document with multiple tasks */ + 'document.footer.open-tasks.placeholder_other': 'Open tasks', + /** The label used in the button in the footer action in a document with a single task */ + 'document.footer.open-tasks.text_one': '{{count}} open task', + /** The label used in the button in the footer action in a document with multiple tasks */ + 'document.footer.open-tasks.text_other': '{{count}} open tasks', + /** Text used in the assignee input when there is no user assigned */ + 'form.input.assignee.no-user-assigned.text': 'Not assigned', + /** Text used in the assignee input when searching and no users are found */ + 'form.input.assignee.search.no-users.text': 'No users found', + /** Placeholder text used in the search box in the assignee input */ + 'form.input.assignee.search.placeholder': 'Search username', + /** Text used in the assignee input when user is not authorized */ + 'form.input.assignee.unauthorized.text': 'Unauthorized', + /** Text used in the assignee input when user is not found */ + 'form.input.assignee.user-not-found.text': 'User not found', + /** The label used in the create more toggle */ + 'form.input.create-more.text': 'Create more', + /** The label used in the date input to remove the current value */ + 'form.input.date.buttons.remove.text': 'Remove', + /** Placeholder text used in the description input */ + 'form.input.description.placeholder': 'Optional additional description', + /** The label used in the target input to remove the current value */ + 'form.input.target.buttons.remove.text': 'Remove target content', + /** The text used in the target input when encountering a schema error */ + 'form.input.target.error.schema-not-found': 'Schema not found', + /** The placeholder text used in the target input for the search component */ + 'form.input.target.search.placeholder': 'Search document', + /** The placeholder text for the title input */ + 'form.input.title.placeholder': 'Task title', + /** The status error message presented when the user does not supply a title */ + 'form.status.error.title-required': 'Title is required', + /** The status message upon successful creation of a task */ + 'form.status.success': 'Task created', + /** The text displayed when no tasks are found */ + 'list.empty.text': 'No tasks', + /** The label for the copy link menu item */ + 'menuitem.copylink.text': 'Copy link to task', + /** The label for the delete task menu item */ + 'menuitem.delete.text': 'Delete task', + /** The label for the duplicate task menu item */ + 'menuitem.duplicate.text': 'Duplicate task', + /** Fragment used to construct the first entry in the activity log */ + 'panel.activity.created-fragment': 'created this task', + /** The title of the activity section of the task */ + 'panel.activity.title': 'Activity', + /** The text used in the activity log when unable to find the user */ + 'panel.activity.unknown-user': 'Unknown user', + /** The tooltip for the close button for the task panel */ + 'panel.close.tooltip': 'Close sidebar', + /** The placeholder text for the comment text box */ + 'panel.comment.placeholder': 'Add a comment...', + /** The title used in the task panel when showing the create task form */ + 'panel.create.title': 'Create', + /** The title used in the drafts pulldown */ + 'panel.drafts.title': 'Drafts', + /** The tooltip for the task navigation component */ + 'panel.navigation.tooltip': 'Open tasks', + /** Title of the Tasks panel */ + 'panel.title': 'Tasks', +}) + +/** + * @alpha + */ +export type TasksLocaleResourceKeys = keyof typeof tasksLocaleStrings + +export default tasksLocaleStrings diff --git a/packages/sanity/src/tasks/index.ts b/packages/sanity/src/tasks/index.ts index 0e19448eac8..7e0262595ce 100644 --- a/packages/sanity/src/tasks/index.ts +++ b/packages/sanity/src/tasks/index.ts @@ -1,2 +1,3 @@ +export {tasksLocaleNamespace, type TasksLocaleResourceKeys} from './i18n' export * from './plugin' export * from './src/tasks' diff --git a/packages/sanity/src/tasks/plugin/TaskCreateAction.tsx b/packages/sanity/src/tasks/plugin/TaskCreateAction.tsx index bc7fa986cd2..1f1e8893f94 100644 --- a/packages/sanity/src/tasks/plugin/TaskCreateAction.tsx +++ b/packages/sanity/src/tasks/plugin/TaskCreateAction.tsx @@ -1,7 +1,8 @@ import {TaskIcon} from '@sanity/icons' import {useCallback} from 'react' -import {type DocumentActionDescription} from 'sanity' +import {type DocumentActionDescription, useTranslation} from 'sanity' +import {tasksLocaleNamespace} from '../i18n' import {useTasksEnabled, useTasksNavigation} from '../src' export function TaskCreateAction(): DocumentActionDescription | null { @@ -13,12 +14,14 @@ export function TaskCreateAction(): DocumentActionDescription | null { setViewMode({type: 'create'}) }, [handleOpenTasks, setViewMode]) + const {t} = useTranslation(tasksLocaleNamespace) + if (!enabled) return null return { icon: TaskIcon, - label: 'Create new task', - title: 'Create new task', + label: t('actions.create.text'), + title: t('actions.create.text'), group: ['paneActions'], onHandle: handleCreateTaskFromDocument, } diff --git a/packages/sanity/src/tasks/plugin/TasksFooterOpenTasks.tsx b/packages/sanity/src/tasks/plugin/TasksFooterOpenTasks.tsx index 048b32dcdd0..49c82080b22 100644 --- a/packages/sanity/src/tasks/plugin/TasksFooterOpenTasks.tsx +++ b/packages/sanity/src/tasks/plugin/TasksFooterOpenTasks.tsx @@ -1,9 +1,11 @@ import {TaskIcon} from '@sanity/icons' import {Badge, useMediaIndex} from '@sanity/ui' import {useCallback, useMemo} from 'react' +import {useTranslation} from 'sanity' import styled from 'styled-components' import {Button} from '../../ui-components' +import {tasksLocaleNamespace} from '../i18n' import {useTasks, useTasksEnabled, useTasksNavigation} from '../src' const ButtonContainer = styled.div` @@ -44,9 +46,10 @@ export function TasksFooterOpenTasks() { setActiveTab('document') }, [handleOpenTasks, setActiveTab]) + const {t} = useTranslation(tasksLocaleNamespace) + if (pendingTasks.length === 0 || !enabled) return null - const pluralizedTask = `task${pendingTasks.length > 1 ? 's' : ''}` if (mediaIndex < 3) { return ( @@ -56,7 +59,9 @@ export function TasksFooterOpenTasks() { size={'large'} onClick={handleOnClick} tooltipProps={{ - content: `Open ${pluralizedTask}`, + content: t('document.footer.open-tasks.placeholder', { + count: pendingTasks.length, + }), }} /> @@ -68,8 +73,12 @@ export function TasksFooterOpenTasks() { return (