diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyDefinition.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyDefinition.tsx index c482bf1c0c9ee..cfc403d3daee3 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyDefinition.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyDefinition.tsx @@ -38,7 +38,7 @@ const PolicyDefinition = ({
@@ -54,17 +54,14 @@ const PolicyDefinition = ({ ].join(' ')} >

- This expression will be added to queries that refer to the table if - row-level security is enabled. + 如果启用了行级安全性,此表达式将添加到对表的查询中。

- Rows for which the expression returns true will be visible. Any rows for - which the expression returns false or null will not be visible to the user - (in a SELECT), and will not be available for modification (in an UPDATE or - DELETE). + 对于返回 true 的表达式的行对将用户可见。对于返回 false 或 null 的表达式的行,将对用户不可见 + (SELECT 操作),并且也不能修改(UPDATE 或 DELETE操作)。

- Such rows are silently suppressed - no error is reported. + 这些行将被静默限制,不会报告错误。

@@ -72,7 +69,7 @@ const PolicyDefinition = ({

- Provide a SQL conditional expression that returns a boolean. + 提供一个返回布尔值的 SQL 条件表达式。

@@ -85,7 +82,7 @@ const PolicyDefinition = ({
@@ -101,17 +98,15 @@ const PolicyDefinition = ({ ].join(' ')} >

- This expression will be used in INSERT and UPDATE queries against the table - if row-level security is enabled. + 如果启用额行级安全性, + 此表达式将在对表的 INSERT 和 UPDATE 查询中使用。

- Only rows for which the expression evaluates to true will be allowed. An - error will be thrown if the expression evaluates to false or null for any of - the records inserted or any of the records that result from the update. + 只有对于表达式返回为 true 的行才会被允许操作。如果表达式返回为 false 或 null, + 对于任何插入操作的新记录或者更新操作返回的记录将会抛出错误。

- Note that this expression is evaluated against the proposed new contents of - the row, not the original contents. + 请注意,此表达式是针对新行的数据进行求值,而不是行的原先的数据。

@@ -119,7 +114,7 @@ const PolicyDefinition = ({

- Provide a SQL conditional expression that returns a boolean. + 提供一个返回布尔值的 SQL 条件表达式。

diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyEditorFooter.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyEditorFooter.tsx index 95de3c6d6aafb..1c38e2dec2ab4 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyEditorFooter.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyEditorFooter.tsx @@ -16,11 +16,11 @@ const PolicyEditorFooter = ({
{showTemplates && ( )}
diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/PolicyEditorModal.constants.ts b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/PolicyEditorModal.constants.ts index f59eb3d10d0ac..61a2c197c1859 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/PolicyEditorModal.constants.ts +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/PolicyEditorModal.constants.ts @@ -18,14 +18,14 @@ export const getGeneralPolicyTemplates = (schema: string, table: string): Policy { id: 'policy-1', preview: false, - templateName: 'Enable read access to everyone', + templateName: '允许任何人读取表', description: - 'This policy gives read access to your table for all users via the SELECT operation.', + '此策略允许所有用户通过 SELECT 操作读取您的表。', statement: ` create policy "Enable read access for all users" on "${schema}"."${table}" for select using (true);`.trim(), - name: 'Enable read access for all users', + name: '允许所有用户读取表', definition: 'true', check: '', command: 'SELECT', @@ -34,14 +34,14 @@ for select using (true);`.trim(), { id: 'policy-2', preview: false, - templateName: 'Enable insert access for authenticated users only', - description: 'This policy gives insert access to your table for all authenticated users only.', + templateName: '仅允许经过身份验证的用户插入数据', + description: '此策略仅允许经过身份验证的用户向您的表中插入数据。', statement: ` create policy "Enable insert for authenticated users only" on "${schema}"."${table}" for insert to authenticated with check (true);`.trim(), - name: 'Enable insert for authenticated users only', + name: '仅允许经过身份验证的用户插入数据', definition: '', check: 'true', command: 'INSERT', @@ -50,9 +50,9 @@ with check (true);`.trim(), { id: 'policy-3', preview: false, - templateName: 'Enable update access for users based on their email *', + templateName: '基于用户的电子邮件允许用户更新数据 *', description: - 'This policy assumes that your table has a column "email", and allows users to update rows which the "email" column matches their email.', + '此策略假定您的表有“email”列,只允许用户更新匹配其电子邮件的行。', statement: ` create policy "Enable update for users based on email" on "${schema}"."${table}" @@ -61,7 +61,7 @@ for update using ( ) with check ( (select auth.jwt()) ->> 'email' = email );`.trim(), - name: 'Enable update for users based on email', + name: '基于用户的电子邮件允许用户更新数据', definition: `(select auth.jwt()) ->> 'email' = email`, check: `(select auth.jwt()) ->> 'email' = email`, command: 'UPDATE', @@ -70,16 +70,16 @@ for update using ( { id: 'policy-4', preview: false, - templateName: 'Enable delete access for users based on their user ID *', + templateName: '基于用户的 ID 允许用户删除数据 *', description: - 'This policy assumes that your table has a column "user_id", and allows users to delete rows which the "user_id" column matches their ID', + '此策略假定您的表有“user_id”列,只允许用户删除匹配其 ID 的行。', statement: ` create policy "Enable delete for users based on user_id" on "${schema}"."${table}" for delete using ( (select auth.uid()) = user_id );`.trim(), - name: 'Enable delete for users based on user_id', + name: '基于 user_id 允许用户删除数据', definition: '(select auth.uid()) = user_id', check: '', command: 'DELETE', @@ -88,16 +88,16 @@ for delete using ( { id: 'policy-5', preview: false, - templateName: 'Enable insert access for users based on their user ID *', + templateName: '基于用户的 ID 允许用户插入数据 *', description: - 'This policy assumes that your table has a column "user_id", and allows users to insert rows which the "user_id" column matches their ID', + '此策略假定您的表有“user_id”列,只允许用户插入匹配其 ID 的行。', statement: ` create policy "Enable insert for users based on user_id" on "${schema}"."${table}" for insert with check ( (select auth.uid()) = user_id );`.trim(), - name: 'Enable insert for users based on user_id', + name: '基于 user_id 允许用户插入数据', definition: '', check: '(select auth.uid()) = user_id', command: 'INSERT', @@ -106,12 +106,12 @@ for insert with check ( { id: 'policy-6', preview: true, - name: 'Policy with table joins', - templateName: 'Policy with table joins', + name: '使用表关联的策略', + templateName: '使用表关联的策略', description: ` -Query across tables to build more advanced RLS rules +跨表查询以构建更高级的 RLS 规则 -Assuming 2 tables called \`teams\` and \`members\`, you can query both tables in the policy to control access to the members table.`, +假定有两张表,分别称为 \`teams\` 和 \`members\`,您可以在策略中查询这两个表以控制对 members 表的访问权限。`, statement: ` create policy "Members can update team details if they belong to the team" on teams for update using ( @@ -128,11 +128,11 @@ on teams for update using ( { id: 'policy-7', preview: true, - templateName: 'Policy with security definer functions', + templateName: '使用 security definer 函数的策略', description: ` -Useful in a many-to-many relationship where you want to restrict access to the linking table. +在多对多的表关系中很有用,您希望限制对关联表的访问权限。 -Assuming 2 tables called \`teams\` and \`members\`, you can use a security definer function in combination with a policy to control access to the members table.`.trim(), +假定有两张表,分别称为 \`teams\` 和 \`members\`,您可以在策略中使用 security definer 函数来控制对 members 表的访问权限。`.trim(), statement: ` create or replace function get_teams_for_user(user_id uuid) returns setof bigint as $$ @@ -145,7 +145,7 @@ for all using ( team_id in (select get_teams_for_user(auth.uid())) ); `.trim(), - name: 'Policy with security definer functions', + name: '使用 security definer 函数的策略', definition: 'team_id in (select get_teams_for_user(auth.uid()))', check: '', command: 'ALL', @@ -154,12 +154,12 @@ for all using ( { id: 'policy-8', preview: true, - name: 'Policy to implement Time To Live (TTL)', - templateName: 'Policy to implement Time To Live (TTL)', + name: '实现 TTL 功能的策略', + templateName: '实现 TTL 功能的策略', description: ` -Implement a TTL-like feature that you see in Instagram stories or Snapchat where messages expire after a day. +实现类似于 Instagram storie 或 Snapchat 中的消息在一天后过期的 TTL 功能。 -Rows under the table are available only if they have been created within the last 24 hours.`, +表中的行仅在创建后 24 小时内可用。`, statement: ` create policy "Stories are live for a day" on "${schema}"."${table}" @@ -179,14 +179,14 @@ export const getRealtimePolicyTemplates = (): PolicyTemplate[] => { { id: 'policy-broadcast-1', preview: false, - templateName: 'Allow listening for broadcasts for authenticated users only', - description: 'This policy allows listening for broadcasts for authenticated users only.', + templateName: '仅允许通过身份验证的用户监听广播消息', + description: '此策略仅允许通过身份验证的用户监听广播消息。', statement: ` create policy "Allow listening for broadcasts for authenticated users only" on realtime.messages for select to authenticated using ( realtime.messages.extension = 'broadcast' );`.trim(), - name: 'Allow listening for broadcasts for authenticated users only', + name: '仅允许通过身份验证的用户监听广播消息', definition: "realtime.messages.extension = 'broadcast'", check: '', command: 'SELECT', @@ -195,14 +195,14 @@ using ( realtime.messages.extension = 'broadcast' );`.trim(), { id: 'policy-broadcast-2', preview: false, - templateName: 'Allow pushing broadcasts for authenticated users only', - description: 'This policy allows pushing broadcasts for authenticated users only.', + templateName: '仅允许通过身份验证的用户推送广播消息', + description: '此策略仅允许通过身份验证的用户推送广播消息。', statement: ` create policy "Allow pushing broadcasts for authenticated users only" ON realtime.messages for insert TO authenticated with check ( realtime.messages.extension = 'broadcast' );`.trim(), - name: 'Allow pushing broadcasts for authenticated users only', + name: '仅允许通过身份验证的用户推送广播消息', definition: "realtime.messages.extension = 'broadcast'", check: "realtime.messages.extension = 'broadcast'", command: 'INSERT', @@ -211,13 +211,13 @@ with check ( realtime.messages.extension = 'broadcast' );`.trim(), { id: 'policy-broadcast-3', preview: false, - templateName: 'Allow listening for broadcasts from a specific channel', - description: 'This policy allows listening for broadcasts from a specific channel.', + templateName: '仅允许从特定频道监听广播消息', + description: '此策略仅允许从特定频道监听广播消息。', statement: ` create policy "Allow listening for broadcasts from a specific channel" on realtime.messages for select using ( realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name' );`.trim(), - name: 'Allow listening for broadcasts from a specific channel', + name: '仅允许从特定频道监听广播消息', definition: `realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name'`, check: '', command: 'SELECT', @@ -226,13 +226,13 @@ using ( realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channe { id: 'policy-broadcast-4', preview: false, - templateName: 'Allow pushing broadcasts to specific channel', - description: 'This policy allow pushing broadcasts to specific channel.', + templateName: '仅允许向特定频道推送广播消息', + description: '此策略仅允许向特定频道推送广播消息。', statement: ` create policy "Allow pushing broadcasts to specific channel" ON realtime.messages for insert with check ( realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name' );`.trim(), - name: 'Allow pushing broadcasts to specific channel', + name: '仅允许向特定频道推送广播消息', definition: `realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name'`, check: `realtime.messages.extension = 'broadcast' AND realtime.topic() = 'channel_name'`, command: 'INSERT', @@ -241,15 +241,14 @@ with check ( realtime.messages.extension = 'broadcast' AND realtime.topic() = 'c { id: 'policy-presences-1', preview: false, - templateName: 'Allow listening for presences on all channels for authenticated users only', - description: - 'This policy enables listening for presences on all channels for all authenticated users only.', + templateName: '仅允许通过身份验证的用户监听所有频道的在线状态', + description: '此策略仅允许通过身份验证的用户监听所有频道的在线状态。', statement: ` create policy "Allow listening for presences on all channels for authenticated users only" on realtime.messages for select to authenticated using ( realtime.messages.extension = 'presence' );`.trim(), - name: 'Allow listening for presences on all channels for authenticated users only', + name: '仅允许通过身份验证的用户监听所有频道的在线状态', definition: "realtime.messages.extension = 'presence'", check: '', command: 'SELECT', @@ -258,16 +257,15 @@ using ( realtime.messages.extension = 'presence' );`.trim(), { id: 'policy-presences-2', preview: false, - templateName: 'Allow broadcasting presences on all channels for authenticated users only', - description: - 'This policy enables broadcasting presences on all channels for all authenticated users only.', + templateName: '仅允许通过身份验证的用户向所有频道广播在线状态', + description: '此策略仅允许通过身份验证的用户向所有频道广播在线状态。', statement: ` create policy "Allow broadcasting presences on all channels for authenticated users only" ON realtime.messages for insert TO authenticated with check ( realtime.messages.extension = 'presence' ); ;`.trim(), - name: 'Allow broadcasting presences on all channels for authenticated users only', + name: '仅允许通过身份验证的用户向所有频道广播在线状态', definition: "realtime.messages.extension = 'presence'", check: "realtime.messages.extension = 'presence'", command: 'INSERT', @@ -276,13 +274,13 @@ with check ( realtime.messages.extension = 'presence' ); { id: 'policy-presences-3', preview: false, - templateName: 'Allow listening for presences from a specific channel', - description: 'This policy enables listening for presences from a specific channel.', + templateName: '仅允许从特定频道监听在线状态', + description: '此策略仅允许从特定频道监听在线状态。', statement: ` create policy "Allow listening for presences from a specific channel" on realtime.messages for select using ( realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name' );`.trim(), - name: 'Allow listening for presences from a specific channel', + name: '仅允许从特定频道监听在线状态', definition: `realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name'`, check: '', command: 'SELECT', @@ -291,14 +289,14 @@ using ( realtime.messages.extension = 'presence' AND realtime.topic() = 'channel { id: 'policy-presences-4', preview: false, - templateName: 'Publish presence to a specific channel', - description: 'This policy allows publishing presence to a specific channel.', + templateName: '向特定频道发布在线状态', + description: '此策略允许向特定频道发布在线状态。', statement: ` create policy "Publish presence to a specific channel" ON realtime.messages for insert with check ( realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name' ); ;`.trim(), - name: 'Publish presence to a specific channel', + name: '向特定频道发布在线状态', definition: `realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name'`, check: `realtime.messages.extension = 'presence' AND realtime.topic() = 'channel_name'`, command: 'INSERT', diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/PolicyEditorModalTitle.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/PolicyEditorModalTitle.tsx index 48e2fa4bbda9c..e1c17657b5838 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/PolicyEditorModalTitle.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/PolicyEditorModalTitle.tsx @@ -24,10 +24,10 @@ const PolicyEditorModalTitle = ({ }: PolicyEditorModalTitleProps) => { const getTitle = () => { if (view === POLICY_MODAL_VIEWS.EDITOR || view === POLICY_MODAL_VIEWS.SELECTION) { - return `${isNewPolicy ? 'Adding new policy to' : 'Editing policy from'} ${schema}.${table}` + return `正在为 ${schema}.${table} ${isNewPolicy ? '添加新策略' : '编辑策略'} ` } if (view === POLICY_MODAL_VIEWS.REVIEW) { - return `Reviewing policy to be ${isNewPolicy ? 'created' : 'updated'} on ${schema}.${table}` + return `正在检查 {schema}.${table} 上${isNewPolicy ? '待创建的' : '待更新的'} 策略$` } } @@ -41,7 +41,7 @@ const PolicyEditorModalTitle = ({ > -

Select a template to use for your new policy

+

请为您的新策略选择一个模板

) @@ -58,7 +58,7 @@ const PolicyEditorModalTitle = ({ icon={} onClick={onToggleFeaturePreviewModal} > - Try Supabase Assistant + 试用 Supabase Assistant )} diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/index.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/index.tsx index 9c7fd55179b75..feed3ffb4284c 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/index.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorModal/index.tsx @@ -123,20 +123,20 @@ const PolicyEditorModal = ({ const { name, definition, check, command } = policyFormFields if (name.length === 0) { - return toast.error('Please provide a name for your policy') + return toast.error('请提供策略的名称') } if (!command) { - return toast.error('Please select an operation for your policy') + return toast.error('请选择策略的操作') } if (['SELECT', 'DELETE'].includes(command) && !definition) { - return toast.error('Please provide a USING expression for your policy') + return toast.error('请提供 USING 表达式') } if (command === 'INSERT' && !check) { - return toast.error('Please provide a WITH CHECK expression for your policy') + return toast.error('请提供 WITH CHECK 表达式') } if (command === 'UPDATE' && !definition && !check) { return toast.error( - 'Please provide either a USING, or WITH CHECK expression, or both for your policy' + '请提供 USING 表达式、WITH CHECK 表达式或两者的组合' ) } const policySQLStatement = createSQLPolicy(policyFormFields, selectedPolicyToEdit) @@ -197,13 +197,12 @@ const PolicyEditorModal = ({ }} >

- There are unsaved changes. Are you sure you want to close the editor? Your changes will - be lost. + 有未保存的更改。确定要关闭编辑器吗?您的更改将会丢失。

{view === POLICY_MODAL_VIEWS.SELECTION ? ( !policy.preview)} - templatesNote="* References a specific column in the table" + templatesNote="* 引用表中特定的列" onUseTemplate={onUseTemplate} /> ) : view === POLICY_MODAL_VIEWS.REVIEW ? ( diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyTemplates/TemplatePreview.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyTemplates/TemplatePreview.tsx index a1dfa78a20c0e..a94fcedced3c9 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyTemplates/TemplatePreview.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyTemplates/TemplatePreview.tsx @@ -20,7 +20,7 @@ const TemplatePreview = ({ selectedTemplate }: TemplatePreviewProps) => {
- +
diff --git a/apps/studio/components/layouts/StorageLayout/StorageMenu.tsx b/apps/studio/components/layouts/StorageLayout/StorageMenu.tsx index 8d8189e388db8..2c8388a694c3c 100644 --- a/apps/studio/components/layouts/StorageLayout/StorageMenu.tsx +++ b/apps/studio/components/layouts/StorageLayout/StorageMenu.tsx @@ -128,7 +128,7 @@ const StorageMenu = () => { 配置} /> -

策略

+

存储策略

{/* diff --git a/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx b/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx index 0f1017c32c8a1..697c4fc6578a7 100644 --- a/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx +++ b/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx @@ -60,21 +60,21 @@ const CustomExpiryModal = ({ onCopyUrl }: CustomExpiryModalProps) => { <>

- 输入 URL 有效的时长: + 输入 URL 的有效时长:

- + - + - + - + diff --git a/apps/studio/components/to-be-cleaned/Storage/StoragePolicies/StoragePolicies.tsx b/apps/studio/components/to-be-cleaned/Storage/StoragePolicies/StoragePolicies.tsx index 5317228fc35c2..b06faf608cf95 100644 --- a/apps/studio/components/to-be-cleaned/Storage/StoragePolicies/StoragePolicies.tsx +++ b/apps/studio/components/to-be-cleaned/Storage/StoragePolicies/StoragePolicies.tsx @@ -176,7 +176,7 @@ const StoragePolicies = () => { return (
-

文件存储策略

+

存储策略

通过策略定义存储桶级别所允许的操作来保护您的文件。

diff --git a/apps/studio/lib/constants/index.ts b/apps/studio/lib/constants/index.ts index f581e347cac78..cd796f01e5231 100644 --- a/apps/studio/lib/constants/index.ts +++ b/apps/studio/lib/constants/index.ts @@ -17,7 +17,7 @@ export const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH ?? '' export const DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ' // should be used for all dayjs formattings shown to the user. Includes timezone info. -export const DATETIME_FORMAT = 'DD MMM YYYY, HH:mm:ss (ZZ)' +export const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss (ZZ)' export const GOTRUE_ERRORS = { UNVERIFIED_GITHUB_USER: 'Error sending confirmation mail', diff --git a/apps/studio/localStores/storageExplorer/StorageExplorerStore.tsx b/apps/studio/localStores/storageExplorer/StorageExplorerStore.tsx index db987c9034998..c2ab854316985 100644 --- a/apps/studio/localStores/storageExplorer/StorageExplorerStore.tsx +++ b/apps/studio/localStores/storageExplorer/StorageExplorerStore.tsx @@ -52,7 +52,7 @@ const DEFAULT_EXPIRY = 10 * 365 * 24 * 60 * 60 // in seconds, default to 10 year const PREVIEW_SIZE_LIMIT = 10000000 // 10MB const BATCH_SIZE = 2 const EMPTY_FOLDER_PLACEHOLDER_FILE_NAME = '.emptyFolderPlaceholder' -const STORAGE_PROGRESS_INFO_TEXT = "Please do not close the browser until it's completed" +const STORAGE_PROGRESS_INFO_TEXT = "完成之前请勿关闭浏览器。" class StorageExplorerStore { private projectRef: string = '' @@ -289,7 +289,7 @@ class StorageExplorerStore { if (!/^[a-zA-Z0-9_-\s]*$/.test(formattedName)) { return UiToast({ variant: 'destructive', - description: 'Folder name contains invalid special characters', + description: '文件夹名称包含无效的特殊字符', duration: 6000, }) } @@ -392,7 +392,7 @@ class StorageExplorerStore { this.addFileToPreviewCache(fileCache) return fileUrl } catch (error) { - console.error('Failed to get file URL', error) + console.error('获取文件的 URL 失败', error) return '' } } @@ -422,7 +422,7 @@ class StorageExplorerStore { // https://stackoverflow.com/a/53058574 private getFilesDataTransferItems = async (items: DataTransferItemList) => { - const { dismiss } = UiToast({ description: 'Retrieving items to upload...' }) + const { dismiss } = UiToast({ description: '正在获取上传的文件...' }) const files: (File & { path: string })[] = [] const queue: FileSystemEntry[] = [] for (const item of items) { @@ -510,13 +510,12 @@ class StorageExplorerStore { toast.error(

- Failed to upload {numberOfFilesRejected} file{numberOfFilesRejected > 1 ? 's' : ''} as{' '} - {numberOfFilesRejected > 1 ? 'their' : 'its'} size - {numberOfFilesRejected > 1 ? 's are' : ' is'} beyond the upload limit of {value} - {unit}. + {numberOfFilesRejected} 个文件{numberOfFilesRejected > 1 ? '' : ''}上传失败,因为 + {numberOfFilesRejected > 1 ? '它们的' : '它的'}大小 + 超出了上传文件的大小限制 {value} {unit}。

- You may change the file size upload limit under Storage in Project Settings. + 您可以在项目设置中更改上传文件的大小限制。

, { duration: 8000 } @@ -565,8 +564,8 @@ class StorageExplorerStore { const toastId = toast.loading( 1 ? 's' : '' + message={`正在上传 ${formattedFilesToUpload.length} 个文件${ + formattedFilesToUpload.length > 1 ? '' : '' }...`} description={STORAGE_PROGRESS_INFO_TEXT} /> @@ -629,7 +628,7 @@ class StorageExplorerStore { if (error) { numberOfFilesUploadedFail += 1 - toast.error(`Failed to upload ${file.name}: ${error.message}`) + toast.error(`上传文件 ${file.name} 失败:${error.message}`) resolve() } else { numberOfFilesUploadedSuccess += 1 @@ -651,8 +650,8 @@ class StorageExplorerStore { toast.loading( 1 ? 's' : '' + message={`正在上传 ${formattedFilesToUpload.length} 个文件${ + formattedFilesToUpload.length > 1 ? '' : '' }...`} description={STORAGE_PROGRESS_INFO_TEXT} />, @@ -674,31 +673,31 @@ class StorageExplorerStore { toast.dismiss(toastId) } else if (numberOfFilesUploadedFail === numberOfFilesToUpload) { toast.error( - `Failed to upload ${numberOfFilesToUpload} file${numberOfFilesToUpload > 1 ? 's' : ''}!`, + `上传 ${numberOfFilesToUpload} 个文件${numberOfFilesToUpload > 1 ? '' : ''}失败!`, { id: toastId } ) } else if (numberOfFilesUploadedSuccess === numberOfFilesToUpload) { toast.success( - `Successfully uploaded ${numberOfFilesToUpload} file${ - numberOfFilesToUpload > 1 ? 's' : '' - }!`, + `成功上传了 ${numberOfFilesToUpload} 个文件${ + numberOfFilesToUpload > 1 ? '' : '' + }!`, { id: toastId } ) } else { toast.success( - `Successfully uploaded ${numberOfFilesUploadedSuccess} out of ${numberOfFilesToUpload} file${ - numberOfFilesToUpload > 1 ? 's' : '' - }!`, + `已成功上传了 ${numberOfFilesToUpload} 个文件中的 ${numberOfFilesUploadedSuccess} 个${ + numberOfFilesToUpload > 1 ? '' : '' + }!`, { id: toastId } ) } } catch (e) { - toast.error('Failed to upload files', { id: toastId }) + toast.error('批量上传文件失败', { id: toastId }) } const t2 = new Date() console.log( - `Total time taken for ${formattedFilesToUpload.length} files: ${((t2 as any) - (t1 as any)) / 1000} seconds` + `上传 ${formattedFilesToUpload.length} 个文件总耗时:${((t2 as any) - (t1 as any)) / 1000} 秒` ) } @@ -709,7 +708,7 @@ class StorageExplorerStore { this.clearSelectedItems() const { dismiss } = UiToast({ - description: 'Please do not close the browser until the move is completed', + description: '完成文件移动前请勿关闭浏览器', duration: Infinity, }) @@ -739,12 +738,12 @@ class StorageExplorerStore { ) if (numberOfFilesMovedFail === this.selectedItemsToMove.length) { - UiToast({ variant: 'destructive', description: 'Failed to move files' }) + UiToast({ variant: 'destructive', description: '移动文件失败' }) } else { UiToast({ - description: `Successfully moved ${ + description: `成功将 ${ this.selectedItemsToMove.length - numberOfFilesMovedFail - } files to ${formattedNewPathToFile.length > 0 ? formattedNewPathToFile : 'the root of your bucket'}`, + } 个文件移动到 ${formattedNewPathToFile.length > 0 ? formattedNewPathToFile : '存储桶根目录'}`, }) } @@ -775,7 +774,7 @@ class StorageExplorerStore { }) return data.publicUrl } catch (error: any) { - toast.error(`Failed to fetch public file preview: ${error.message}`) + toast.error(`获取公开文件的预览失败:${error.message}`) } } else { try { @@ -787,7 +786,7 @@ class StorageExplorerStore { }) return data.signedUrl } catch (error: any) { - toast.error(`Failed to fetch signed url preview: ${error.message}`) + toast.error(`获取签名 URL 文件的预览失败:${error.message}`) } } return '' @@ -820,7 +819,7 @@ class StorageExplorerStore { const toastId = toast.loading( ) @@ -842,7 +841,7 @@ class StorageExplorerStore { toast.loading( , { id: toastId } @@ -867,7 +866,7 @@ class StorageExplorerStore { await Promise.all( parentFolderPrefixes.map((prefix) => this.validateParentFolderEmpty(prefix)) ) - toast.success(`Successfully deleted ${prefixes.length} file(s)`, { id: toastId }) + toast.success(`成功删除了 ${prefixes.length} 个文件`, { id: toastId }) await this.refetchAllOpenedFolders() this.clearSelectedItemsToDelete() } else { @@ -877,14 +876,14 @@ class StorageExplorerStore { downloadFolder = async (folder: StorageItemWithColumn) => { let progress = 0 - const toastId = toast.loading('Retrieving files from folder...') + const toastId = toast.loading('从文件夹中获取文件...') const files = await this.getAllItemsAlongFolder(folder) toast.loading( 1 ? 's' : ''}...`} + message={`正在下载 ${files.length} 个文件${files.length > 1 ? '' : ''}...`} description={STORAGE_PROGRESS_INFO_TEXT} />, { id: toastId } @@ -916,7 +915,7 @@ class StorageExplorerStore { blob: new Blob([blob], { type: fileMimeType }), }) } catch (error) { - console.error('Failed to download file', `${file.prefix}/${file.name}`) + console.error('下载文件失败', `${file.prefix}/${file.name}`) resolve(false) } }) @@ -931,7 +930,7 @@ class StorageExplorerStore { toast.loading( 1 ? 's' : ''}...`} + message={`正在下载 ${files.length} 个文件${files.length > 1 ? '' : ''}...`} description={STORAGE_PROGRESS_INFO_TEXT} />, { id: toastId } @@ -951,7 +950,7 @@ class StorageExplorerStore { const zipWriter = new ZipWriter(zipFileWriter, { bufferedWrite: true }) if (downloadedFiles.length === 0) { - toast.error(`Failed to download files from "${folder.name}"`, { id: toastId }) + toast.error(`从 "${folder.name}" 中下载文件失败`, { id: toastId }) } downloadedFiles.forEach((file) => { @@ -968,10 +967,10 @@ class StorageExplorerStore { toast.success( downloadedFiles.length === files.length - ? `Successfully downloaded folder "${folder.name}"` - : `Downloaded folder "${folder.name}". However, ${ + ? `成功下载了文件夹 "${folder.name}"` + : `成功下载了文件夹 "${folder.name}"。但是,有 ${ files.length - downloadedFiles.length - } files did not download successfully.`, + } 个文件下载失败。`, { id: toastId } ) } @@ -993,7 +992,7 @@ class StorageExplorerStore { const returnBlob = true const showIndividualToast = false const toastId = toast.loading( - `Downloading ${files.length} file${files.length > 1 ? 's' : ''}...` + `正在下载 ${files.length} 个文件${files.length > 1 ? '' : ''}...` ) const promises = formattedFilesWithPrefix.map((file) => { @@ -1016,7 +1015,7 @@ class StorageExplorerStore { toast.loading( 1 ? 's' : ''}...`} + message={`正在下载 ${files.length} 个文件${files.length > 1 ? '' : ''}...`} description={STORAGE_PROGRESS_INFO_TEXT} />, { id: toastId } @@ -1038,14 +1037,14 @@ class StorageExplorerStore { link.click() link.parentNode?.removeChild(link) - toast.success(`Successfully downloaded ${downloadedFiles.length} files`, { id: toastId }) + toast.success(`成功下载了 ${downloadedFiles.length} 个文件`, { id: toastId }) } downloadFile = async (file: StorageItemWithColumn, showToast = true, returnBlob = false) => { const fileName: string = file.name const fileMimeType = file?.metadata?.mimetype ?? undefined - const toastId = showToast ? toast.loading(`Retrieving ${fileName}...`) : undefined + const toastId = showToast ? toast.loading(`获取文件 ${fileName}...`) : undefined const pathToFile = this.openedFolders .slice(0, file.columnIndex) @@ -1073,12 +1072,12 @@ class StorageExplorerStore { link.parentNode?.removeChild(link) window.URL.revokeObjectURL(blob) if (toastId) { - toast.success(`Downloading ${fileName}`, { id: toastId }) + toast.success(`正在下载 ${fileName}`, { id: toastId }) } return true } catch { if (toastId) { - toast.error(`Failed to download ${fileName}`, { id: toastId }) + toast.error(`下载 ${fileName} 失败`, { id: toastId }) } return false } @@ -1104,7 +1103,7 @@ class StorageExplorerStore { to: toPath, }) - toast.success(`Successfully renamed "${originalName}" to "${newName}"`) + toast.success(`成功将 "${originalName}" 重命名为 "${newName}"`) // Clear file preview cache if the renamed file exists in the cache const updatedFilePreviewCache = this.filePreviewCache.filter( @@ -1119,7 +1118,7 @@ class StorageExplorerStore { await this.refetchAllOpenedFolders() } catch (error: any) { - toast.error(`Failed to rename file: ${error.message}`) + toast.error(`重命名文件失败:${error.message}`) } } } @@ -1179,7 +1178,7 @@ class StorageExplorerStore { ) } catch (error: any) { if (!error.message.includes('aborted')) { - toast.error(`Failed to retrieve folder contents from "${folderName}": ${error.message}`) + toast.error(`从 "${folderName}" 中获取文件夹内容失败:${error.message}`) } } } @@ -1220,7 +1219,7 @@ class StorageExplorerStore { }) } catch (error: any) { if (!error.message.includes('aborted')) { - toast.error(`Failed to retrieve more folder contents: ${error.message}`) + toast.error(`获取更多文件夹内容失败:${error.message}`) } } } @@ -1264,7 +1263,7 @@ class StorageExplorerStore { }) return data } catch (error: any) { - toast.error(`Failed to fetch folders: ${error.message}`) + toast.error(`获取文件夹失败:${error.message}`) return [] } }) @@ -1346,7 +1345,7 @@ class StorageExplorerStore { await this.refetchAllOpenedFolders() this.clearSelectedItemsToDelete() - toast.success(`Successfully deleted ${folder.name}`) + toast.success(`成功删除了 ${folder.name}`) } renameFolder = async (folder: StorageItemWithColumn, newName: string, columnIndex: number) => { @@ -1358,7 +1357,7 @@ class StorageExplorerStore { const toastId = toast.loading( ) @@ -1372,7 +1371,7 @@ class StorageExplorerStore { * todo: move this to a util file, as createFolder() uses same logic */ if (newName.includes('/') || newName.includes('\\')) { - return toast.error(`Folder name cannot contain forward or back slashes.`) + return toast.error(`文件夹名称不能包含正斜杠或反斜杠。`) } this.updateRowStatus(originalName, STORAGE_ROW_STATUS.LOADING, columnIndex, newName) @@ -1402,7 +1401,7 @@ class StorageExplorerStore { }) } catch (error) { hasErrors = true - toast.error(`Failed to move ${fromPath} to the new folder`) + toast.error(`移动 ${fromPath} 到新文件夹失败`) } resolve() }) @@ -1419,7 +1418,7 @@ class StorageExplorerStore { toast.loading( , { id: toastId } @@ -1427,9 +1426,9 @@ class StorageExplorerStore { }, Promise.resolve()) if (!hasErrors) { - toast.success(`Successfully renamed folder to ${newName}`, { id: toastId }) + toast.success(`成功将文件夹重命名为 ${newName}`, { id: toastId }) } else { - toast.error(`Renamed folder to ${newName} with some errors`, { id: toastId }) + toast.error(`将文件夹重命名为 ${newName} 时发生错误`, { id: toastId }) } await this.refetchAllOpenedFolders() @@ -1440,7 +1439,7 @@ class StorageExplorerStore { ) this.filePreviewCache = updatedFilePreviewCache } catch (e: any) { - toast.error(`Failed to rename folder to ${newName}: ${e.message}`, { id: toastId }) + toast.error(`将文件夹重命名为 ${newName} 失败:${e.message}`, { id: toastId }) } } @@ -1539,9 +1538,7 @@ class StorageExplorerStore { const updatedFileName = fileName + ` (${itemsWithSameNameInColumn.length + 1})` return fileExt ? `${updatedFileName}.${fileExt}` : updatedFileName } else { - toast.error( - `The name ${name} already exists in the current directory. Please use a different name.` - ) + toast.error(`名称 ${name} 已存在于当前目录。请使用不同的名称。`) return null } } diff --git a/apps/studio/pages/project/[ref]/storage/buckets/[bucketId].tsx b/apps/studio/pages/project/[ref]/storage/buckets/[bucketId].tsx index 89726e6bcea2a..d139f7841acd7 100644 --- a/apps/studio/pages/project/[ref]/storage/buckets/[bucketId].tsx +++ b/apps/studio/pages/project/[ref]/storage/buckets/[bucketId].tsx @@ -25,7 +25,7 @@ const PageLayout: NextPageWithLayout = () => { {isSuccess ? ( !bucket ? (
-

Bucket {bucketId} cannot be found

+

无法找到存储桶 {bucketId}

) : ( @@ -37,6 +37,6 @@ const PageLayout: NextPageWithLayout = () => { ) } -PageLayout.getLayout = (page) => {page} +PageLayout.getLayout = (page) => {page} export default PageLayout diff --git a/apps/studio/pages/project/[ref]/storage/policies.tsx b/apps/studio/pages/project/[ref]/storage/policies.tsx index 18200a699cd57..91aa653a543b3 100644 --- a/apps/studio/pages/project/[ref]/storage/policies.tsx +++ b/apps/studio/pages/project/[ref]/storage/policies.tsx @@ -10,6 +10,6 @@ const StoragePoliciesPage: NextPageWithLayout = () => { ) } -StoragePoliciesPage.getLayout = (page) => {page} +StoragePoliciesPage.getLayout = (page) => {page} export default StoragePoliciesPage