From df9fc4100f8552b6e470239539400e5a337ccc1f Mon Sep 17 00:00:00 2001 From: nichenqin Date: Tue, 26 Nov 2024 11:16:04 +0800 Subject: [PATCH] chore: auth i18n --- .../lib/components/blocks/auth/login.svelte | 32 +- .../blocks/auth/reset-password.svelte | 15 +- .../lib/components/blocks/auth/signup.svelte | 42 +- .../blocks/language/language-picker.svelte | 26 + .../blocks/member/member-menu.svelte | 1 + .../frontend/src/routes/(auth)/+layout.svelte | 7 + .../src/routes/(auth)/login/+page.svelte | 7 +- .../src/routes/(auth)/signup/+page.svelte | 7 +- packages/i18n/src/i18n/en/index.ts | 32 + packages/i18n/src/i18n/es/index.ts | 746 ++++++++++++++++++ packages/i18n/src/i18n/i18n-types.ts | 250 ++++++ packages/i18n/src/i18n/i18n-util.async.ts | 1 + packages/i18n/src/i18n/i18n-util.sync.ts | 2 + packages/i18n/src/i18n/i18n-util.ts | 1 + packages/i18n/src/i18n/ja/index.ts | 36 +- packages/i18n/src/i18n/ko/index.ts | 32 + packages/i18n/src/i18n/zh/index.ts | 34 + 17 files changed, 1223 insertions(+), 48 deletions(-) create mode 100644 apps/frontend/src/lib/components/blocks/language/language-picker.svelte create mode 100644 packages/i18n/src/i18n/es/index.ts diff --git a/apps/frontend/src/lib/components/blocks/auth/login.svelte b/apps/frontend/src/lib/components/blocks/auth/login.svelte index b98497227..dcd8b1a50 100644 --- a/apps/frontend/src/lib/components/blocks/auth/login.svelte +++ b/apps/frontend/src/lib/components/blocks/auth/login.svelte @@ -16,6 +16,7 @@ import autoAnimate from "@formkit/auto-animate" import { LoaderCircleIcon } from "lucide-svelte" import ResetPassword from "$lib/components/blocks/auth/reset-password.svelte" + import { LL } from "@undb/i18n/client" import { page } from "$app/stores" export let registrationEnabled: boolean @@ -38,7 +39,7 @@ try { const { ok } = await fetch("/api/login", { method: "POST", body: JSON.stringify(input) }) if (!ok) { - throw new Error("Failed to login") + throw new Error(LL.auth.loginFailed()) } return } catch (error) { @@ -93,12 +94,12 @@
- Email + {$LL.common.email()} @@ -110,14 +111,14 @@
- + {$LL.auth.forgotPassword()}
@@ -130,29 +131,32 @@ {#if $loginMutation.isPending} {/if} - Login + {$LL.auth.login()}
{#if loginError} - Error - Invalid email or password. + {$LL.common.error()} + {$LL.auth.invalidEmailOrPassword()} {/if}
{#if registrationEnabled}
- Don't have an account? + {$LL.auth.noAccount()} {#if redirect} - Sign up + {$LL.auth.register()} {:else} - Sign up + {$LL.auth.register()} {/if}
{:else}

- Registration is disabled.
Contact your administrator to request access. + {$LL.auth.registerDisabled()} + +
+ {$LL.auth.registerDisabledDescription()}

{/if} {#if githubEnabled || googleEnabled} @@ -161,13 +165,13 @@ {#if githubEnabled} {/if} {#if googleEnabled} {/if} diff --git a/apps/frontend/src/lib/components/blocks/auth/reset-password.svelte b/apps/frontend/src/lib/components/blocks/auth/reset-password.svelte index 732eb23ed..46ee48432 100644 --- a/apps/frontend/src/lib/components/blocks/auth/reset-password.svelte +++ b/apps/frontend/src/lib/components/blocks/auth/reset-password.svelte @@ -9,6 +9,7 @@ import * as Form from "$lib/components/ui/form" import { LoaderCircleIcon } from "lucide-svelte" import * as Alert from "$lib/components/ui/alert" + import { LL } from "@undb/i18n/client" const schema = z.object({ email: z.string().email(), @@ -57,27 +58,27 @@ {#if $resetPasswordMutation.isSuccess} - Email sent! - You can check your email address and follow the steps to reset your password. + {$LL.auth.emailSent()} + {$LL.auth.youCanCheckYourEmailAddressAndFollowTheStepsToResetYourPassword()} {:else}
- Reset password - Enter your email below to reset your password. + {$LL.auth.resetPassword()} + {$LL.auth.enterYourEmailBelowToResetYourPassword()}
- Email + {$LL.common.email()} @@ -89,7 +90,7 @@ {#if $resetPasswordMutation.isPending} {/if} - Reset + {$LL.auth.resetPassword()}
diff --git a/apps/frontend/src/lib/components/blocks/auth/signup.svelte b/apps/frontend/src/lib/components/blocks/auth/signup.svelte index a1193794b..5ff678082 100644 --- a/apps/frontend/src/lib/components/blocks/auth/signup.svelte +++ b/apps/frontend/src/lib/components/blocks/auth/signup.svelte @@ -1,9 +1,7 @@ + + + + + + + + changeLanguage("en")}>English + changeLanguage("zh")}>中文 + changeLanguage("ja")}>日本語 + changeLanguage("ko")}>한국어 + changeLanguage("es")}>Español + + + diff --git a/apps/frontend/src/lib/components/blocks/member/member-menu.svelte b/apps/frontend/src/lib/components/blocks/member/member-menu.svelte index 8088274d2..39fb9dd19 100644 --- a/apps/frontend/src/lib/components/blocks/member/member-menu.svelte +++ b/apps/frontend/src/lib/components/blocks/member/member-menu.svelte @@ -84,6 +84,7 @@ changeLanguage("zh")}>中文 changeLanguage("ja")}>日本語 changeLanguage("ko")}>한국어 + changeLanguage("es")}>Español diff --git a/apps/frontend/src/routes/(auth)/+layout.svelte b/apps/frontend/src/routes/(auth)/+layout.svelte index 09487b1b3..309577cbe 100644 --- a/apps/frontend/src/routes/(auth)/+layout.svelte +++ b/apps/frontend/src/routes/(auth)/+layout.svelte @@ -1,3 +1,10 @@ + +
+
+ +
diff --git a/apps/frontend/src/routes/(auth)/login/+page.svelte b/apps/frontend/src/routes/(auth)/login/+page.svelte index fd0449b02..357bb768a 100644 --- a/apps/frontend/src/routes/(auth)/login/+page.svelte +++ b/apps/frontend/src/routes/(auth)/login/+page.svelte @@ -4,6 +4,7 @@ import type { PageData } from "./$types" import Logo from "$lib/images/logo.svg" import { goto } from "$app/navigation" + import { LL } from "@undb/i18n/client" export let data: PageData @@ -39,7 +40,7 @@ Light bulb - Login to your account and accept the invitation + {$LL.auth.loginToYourAccountAndAcceptTheInvitation()}

@@ -70,8 +71,8 @@
-

Undb Login

-

Enter your email below to login to your account.

+

Undb {$LL.auth.login()}

+

{$LL.auth.loginWithEmailDescription()}

Light bulb - Create account and accept invitation + {$LL.auth.createAccountAndAcceptInvitation()}

@@ -68,8 +69,8 @@
-

Undb Sign Up

-

Enter your information to create an account.

+

Undb {$LL.auth.register()}

+

{$LL.auth.enterYourInformationToCreateAnAccount()}

= { + eq: "igual a", + neq: "no igual a", + contains: "contiene", + does_not_contain: "no contiene", + starts_with: "comienza con", + ends_with: "termina con", + is_empty: "está vacío", + is_not_empty: "no está vacío", + min: "mínimo", + max: "máximo", + gt: "mayor que", + gte: "mayor o igual que", + lt: "menor que", + lte: "menor o igual que", + in: "está en lista", + nin: "no está en lista", + any_of: "cualquiera de", + not_any_of: "ninguno de", + is_same_day: "es el mismo día", + is_not_same_day: "no es el mismo día", + is_tody: "hoy", + is_not_today: "no es hoy", + is_after_today: "después de hoy", + is_before_today: "antes de hoy", + is_tomorrow: "mañana", + is_not_tomorrow: "no es mañana", + is_after_tomorrow: "después de mañana", + is_before_tommorow: "antes de mañana", + is_yesterday: "ayer", + is_not_yesterday: "no es ayer", + is_after_yesterday: "después de ayer", + is_before_yesterday: "antes de ayer", + is_before: "antes", + is_not_before: "no es antes", + is_after: "después", + is_not_after: "no es después", + is_true: "verdadero", + is_false: "falso" +} + +const fieldTypes: Record = { + string: "texto", + longText: "texto largo", + number: "número", + date: "fecha", + dateRange: "rango de fecha", + id: "ID", + createdAt: "fecha de creación", + autoIncrement: "incremento automático", + updatedAt: "fecha de actualización", + createdBy: "creador", + updatedBy: "actualizador", + reference: "referencia", + rollup: "rollup", + select: "seleccionar", + rating: "calificación", + email: "correo electrónico", + url: "URL", + attachment: "archivo adjunto", + json: "JSON", + checkbox: "casilla de verificación", + user: "usuario", + currency: "moneda", + duration: "duración", + button: "botón", + percentage: "porcentaje", + formula: "fórmula" +} + +const rollupFns: Record = { + min: "mínimo", + max: "máximo", + sum: "suma", + average: "promedio", + count: "conteo", + lookup: "consulta" +} + +const aggregateFns: Record = { + min: "mínimo", + max: "máximo", + sum: "suma", + count: "conteo", + count_empty: "conteo de valores vacíos", + count_uniq: "conteo de valores únicos", + count_not_empty: "conteo de valores no vacíos", + percent_empty: "porcentaje de valores vacíos", + percent_not_empty: "porcentaje de valores no vacíos", + percent_uniq: "porcentaje de valores únicos", + avg: "promedio", + count_true: "conteo de valores verdaderos", + count_false: "conteo de valores falsos", + percent_true: "porcentaje de valores verdaderos", + percent_false: "porcentaje de valores falsos", + start_max: "máximo de fecha de inicio", + end_max: "máximo de fecha de finalización", + start_min: "mínimo de fecha de inicio", + end_min: "mínimo de fecha de finalización" +} + + +const macros: Record = { + "@me": "usuario actual", + "@now": "ahora", + "@today": "hoy", + "@yesterday": "ayer", + "@tomorrow": "mañana" +} + +const viewTypes: Record = { + grid: "cuadrícula", + kanban: "kanban", + gallery: "galería", + list: "lista", + calendar: "calendario", + pivot: "pivote" +} + +const widgetTypes: Record = { + aggregate: "agregado", + chart: "gráfico", + table: "tabla" +} + +const timeScales: Record = { + month: "mes", + week: "semana", + day: "día" +} + +const record = { + label: 'registro', + labels: 'registros', + search: 'búsqueda de registro...', + openMenu: 'abrir menú', + create: 'crear registro', + update: 'actualizar registro', + delete: 'eliminar registro', + viewRecordDetail: 'ver detalle del registro', + copyRecordId: 'copiar ID de registro', + createByForm: 'crear por formulario', + duplicateRecord: 'duplicar registro', + includeDate: "incluir fecha", + detail: 'detalle del registro', + duplicate: 'duplicar {n|número} registros', + updateRecords: 'actualizar {n|número} registros', + bulkUpdateRecords: 'actualizar en masa {n|número} registros', + deleteRecords: 'eliminar {n|número} registros', + confirmDeleteRecord: '¿Desea eliminar el registro?', + confirmDeleteRecordDescription: 'Esta operación no se puede cancelar. Esta operación eliminará permanentemente el registro y eliminará los datos del servidor.', + confirmDeleteRecords: '¿Desea eliminar {n|número} registros?', + confirmDeleteRecordsDescription: 'Esta operación no se puede cancelar. Esta operación eliminará permanentemente los registros y eliminará los datos del servidor.', + confirmDuplicateRecords: '¿Duplicar {n|número} registros?', + confirmDuplicateRecordsDescription: 'Esta operación duplicará {n|número} registros y copiará los datos del servidor.', + confirmDuplicateRecord: '¿Duplicar registro?', + confirmDuplicateRecordDescription: 'Creará un nuevo registro con un nuevo ID.', + failedToDuplicateRecord: 'fallo al duplicar registro', + failedToDeleteRecord: 'fallo al eliminar registro', + copiedRecordId: 'Copió el ID del registro al portapapeles', + createdRecord: '¡Registro creado!', + bulkUpdate: { + title: 'Actualizar registros?', + description: 'Los campos seleccionados se actualizarán', + updateWithCondition: 'Usar condición para actualizar', + addField: 'Agregar campo de actualización', + selectColumns: 'Seleccionar columnas para actualizar', + updated: 'Actualizado', + selectAll: 'Seleccionar todo', + removeAll: 'Deseleccionar todo', + continue: 'Continuar', + noRecordsUpdated: 'No hay registros actualizados', + recordsUpdated: '{count} registros actualizados correctamente', + button: 'Actualizar en masa' + }, + reference: { + link: 'enlace de registro', + linked: '{n|número} registros vinculados' + }, + button: { + confirmToUpdate: 'Confirmar actualización', + confirmToUpdateDescription: 'Campo que se actualizará cuando se haga clic en el botón', + }, + noRecord: 'No hay registros', + showHiddenFields: 'Mostrar {n|número} campos ocultos', + hideHiddenFields: 'Ocultar {n|número} campos ocultos' +} + +const form = { + label: 'formulario', + create: 'crear formulario', + noForms: '{tableName} no hay formularios', + noFormsDescription: 'Puede recoger datos del formulario.', + addDescription: 'Agregar descripción', + condition: 'condición', + invalidCondition: 'Condición inválida', + setDefaultValue: 'Establecer valor predeterminado de {field}', + formField: 'Campo de formulario', + fieldsSelected: '{n} campos seleccionados', + searchFormField: 'Buscar campo de formulario...', + selectAllFields: 'Seleccionar todos los campos', + hideFields: 'Ocultar campos', + showFields: 'Mostrar campos', + noFieldsFound: 'No se encontró el campo con el título `{q}`', + formSetting: 'Configuración del formulario', + duplicateForm: 'Duplicar formulario', + deleteForm: 'Eliminar formulario', + duplicateSuccess: 'Duplicar formulario exitoso', + backgroundColor: 'Color de fondo', + autoAddNewField: 'Agregar automáticamente al formulario', + autoAddNewFieldDescription: 'Se mostrará automáticamente al crear el formulario.', + deleteFormConfirm: 'Eliminar formulario: {name}?', + deleteFormDescription: 'El formulario se eliminará permanentemente.', + duplicateFormDialog: 'Duplicar formulario: {name}?', + duplicateFormDialogDescription: 'El formulario se duplicará.', + setName: 'Establecer nombre del formulario', + enableCondition: 'Habilitar condición' +} + +const common = { + tables: 'tablas', + table: 'tabla', + filters: 'filtros', + color: 'color', + select: 'Seleccionar tabla...', + search: 'Buscar tabla...', + noTablesFound: 'No hay tablas', + sorts: { + sort: 'ordenar', + add: 'Agregar ordenación', + empty: 'Ordenación vacía', + direction: { + asc: 'ascendente', + desc: 'descendente' + } + }, + fields: 'campos', + filter: { + empty: 'No hay condiciones de filtro' + }, + condition: { + add: 'Agregar condición', + addGroup: 'Agregar grupo de condiciones' + }, + submit: 'Enviar', + where: 'donde', + searchOp: 'Buscar operación...', + colorEmpty: 'Color vacío', + updateName: 'Actualizar nombre de la tabla', + duplicateTable: 'Duplicar tabla', + deleteTable: 'Eliminar tabla', + create: 'Crear tabla', + import: 'Importar tabla' +} + + const field = { + field: 'campo', + fields: 'lista de campos', + create: 'crear campo', + created: '¡Campo creado!', + update: 'actualizar campo', + delete: 'eliminar campo', + deleteConfirm: '¿Desea eliminar el campo?', + duplicate: 'duplicar campo', + duplicateDescription: '¿Desea duplicar el siguiente campo?', + hidden: '{n|número} campos ocultos', + searchTableFields: 'Buscar campos de la tabla {table}...', + selectField: 'Seleccionar campo...', + empty: 'No hay campos', + min: 'Valor mínimo', + max: 'Valor máximo', + searchType: 'Buscar tipo de campo...', + defaultValue: { + label: 'Valor predeterminado', + placeholder: 'Valor predeterminado...', + invalid: 'Valor predeterminado inválido', + invalidDescription: 'El valor predeterminado es inválido. No se guardará el valor predeterminado.', + markAsRequired: 'Marcar como campo obligatorio.' + }, + display: { + label: 'Mostrar campo', + markAsDisplay: 'Marcar el campo como campo de visualización.' + }, + id: { + placeholder: 'Generado automáticamente...' + }, + string: { + min: 'Longitud mínima', + max: 'Longitud máxima' + }, + longText: { + allowRichText: 'Permitir texto enriquecido válido.' + }, + duration: { + min: "Valor mínimo", + max: "Valor máximo", + minPlaceholder: "Valor mínimo...", + maxPlaceholder: "Valor máximo..." + }, + number: { + min: 'Valor mínimo', + max: 'Valor máximo', + minPlaceholder: 'Valor mínimo...', + maxPlaceholder: 'Valor máximo...' + }, + currency: { + symbol: 'Símbolo', + min: 'Valor mínimo', + max: 'Valor máximo', + minPlaceholder: 'Valor mínimo...', + maxPlaceholder: 'Valor máximo...' + }, + percentage: { + min: 'Valor mínimo', + max: 'Valor máximo', + minPlaceholder: 'Valor mínimo...', + maxPlaceholder: 'Valor máximo...' + }, + date: { + format: 'Formato de fecha', + includeTime: 'Incluir tiempo', + timeFormat: 'Formato de tiempo', + selectMacro: 'Seleccionar macro...' + }, + dateRange: { + format: 'Formato de fecha', + includeTime: 'Incluir tiempo', + timeFormat: 'Formato de tiempo' + }, + formula: { + label: 'Fórmula', + placeholder: 'Fórmula...', + syntax: 'Sintaxis', + examples: 'Ejemplos' + }, + select: { + option: { + label: 'Opción', + add: 'Agregar opción', + selectDefault: 'Seleccionar opción predeterminada...', + search: 'Buscar opción...', + noOptionFound: 'No hay opciones', + update: 'Actualizar opción', + delete: 'Eliminar opción', + createRecord: 'Crear registro en la opción seleccionada', + create: 'Crear opción' + }, + allowAddMultiple: 'Permitir agregar múltiples opciones', + changeFromMultipleToSingle: 'Cambiar de múltiples opciones a una sola opción!', + changeFromMultipleToSingleDescription: 'Solo se mantendrá la primera opción.', + min: 'Número mínimo de elementos', + max: 'Número máximo de elementos', + minPlaceholder: 'Número mínimo de elementos...', + maxPlaceholder: 'Número máximo de elementos...' + }, + attachment: { + min: 'Número mínimo de elementos', + max: 'Número máximo de elementos', + minPlaceholder: 'Número mínimo de elementos...', + maxPlaceholder: 'Número máximo de elementos...' + }, + user: { + allowAddMultiple: 'Permitir agregar múltiples usuarios', + changeFromMultipleToSingle: 'Cambiar de múltiples opciones a una sola opción!', + changeFromMultipleToSingleDescription: 'Solo se mantendrá la primera opción.', + min: 'Número mínimo de elementos', + max: 'Número máximo de elementos', + minPlaceholder: 'Número mínimo de elementos...', + maxPlaceholder: 'Número máximo de elementos...' + }, + reference: { + foreignTable: 'Tabla externa', + createSymmetricField: 'Crear campo simétrico', + limitRecordSelectionToCondition: 'Limitar la selección de registros a una condición.', + min: 'Número mínimo de elementos', + max: 'Número máximo de elementos', + minPlaceholder: 'Número mínimo de elementos...', + maxPlaceholder: 'Número máximo de elementos...' + }, + rollup: { + referenceField: 'Campo de referencia', + selectReferenceField: 'Seleccionar campo de referencia...', + foreignRollupField: 'Campo de agregado externo', + aggregateFunction: 'Función de agregado' + }, + button: { + label: 'Etiqueta', + disabledWhen: 'Condición para deshabilitar el botón', + updateValueWhenClickButton: 'Actualizar valor cuando se haga clic en el botón', + confirmBeforeUpdate: 'Confirmar antes de actualizar', + addAnotherFieldToUpdate: 'Agregar otro campo de actualización', + valueToUpdate: 'Valor para actualizar...' + } + } + +const view = { + field: { + showAllFields: 'Mostrar todos los campos', + hideAllFields: 'Ocultar todos los campos', + showSystemFields: 'Mostrar campos del sistema', + hideSystemFields: 'Ocultar campos del sistema' + }, + widget: { + title: 'Vista de widget', + empty: 'No hay widgets', + add: 'Agregar widget' + }, + kanban: { + kanban: 'Kanban', + update: 'Actualizar vista de Kanban', + view: 'Vista de Kanban', + field: 'Campo de Kanban', + groupBy: 'Agrupar por tipo de campo', + noSelectField: 'No seleccionar campo de tipo', + noOption: 'Sin opción', + collapseLane: 'Colapsar' + }, + gallery: { + gallery: 'Galería', + update: 'Actualizar vista de galería', + view: 'Vista de galería', + field: 'Campo de galería', + groupBy: 'Agrupar por tipo de archivo', + noAttachmentField: 'No hay campo de tipo de archivo' + }, + calendar: { + calendar: 'Calendario', + update: 'Actualizar vista de calendario', + view: 'Vista de calendario', + field: 'Campo de calendario', + groupBy: 'Agrupar por campo de fecha', + select: 'Seleccionar tipo de campo para agrupar el calendario', + selectField: 'Seleccionar campo de calendario', + noDateField: 'No hay campo de fecha', + scope: { + selectedDate: 'Fecha seleccionada', + withoutDate: 'Sin fecha', + thisMonth: 'Este mes', + allRecords: 'Todos los registros', + thisWeek: 'Esta semana', + } + }, + pivot: { + pivot: 'Pivote', + update: 'Actualizar vista de pivote', + view: 'Vista de pivote', + columnLabel: 'Etiqueta de columna', + rowLabel: 'Etiqueta de fila', + swap: 'Intercambiar etiqueta de columna y fila', + aggregate: 'Agregado', + aggregateFn: { + sum: 'Suma', + count: 'Conteo', + average: 'Promedio', + max: 'Valor máximo', + min: 'Valor mínimo' + }, + value: 'Valor', + selectField: 'Seleccionar campo para agregado de datos del pivote...' + }, + type: 'Tipo de vista', + create: 'Crear vista', + updateName: 'Actualizar nombre de la vista', + updated: 'Vista actualizada', + duplicateView: 'Duplicar vista', + deleteView: 'Eliminar vista', + downloadView: 'Descargar vista', + downloadAsExcel: 'Descargar como Excel', + downloadAsCSV: 'Descargar como CSV', + downloadAsJSON: 'Descargar como JSON', + setAsDefaultView: 'Establecer como vista predeterminada', +} + +const aggregate = { + searchType: 'Buscar tipo de agregado...', + selectField: 'Seleccionar campo para agregado...' +} + +const dashboard = { + dashboards: 'Paneles de control', + create: 'Crear panel de control', + nameDescription: 'Nombre de visualización pública del panel de control.', + updateName: 'Actualizar nombre del panel de control', + duplicateDashboard: 'Duplicar panel de control', + deleteDashboard: 'Eliminar panel de control', + confirmDeleteDashboard: '¿Desea eliminar el panel de control?', + confirmDeleteDashboardDescription: 'Esta operación no se puede cancelar. Esta operación eliminará permanentemente el panel de control y eliminará los datos del servidor.', + duplicateDashboardDescription: '¿Desea duplicar el panel de control?', + duplicateDashboardConfirm: 'Duplicar panel de control', + updateDashboard: 'Actualizar panel de control', +} + +const base = { + name: 'Nombre de Base', + noBases: 'No hay bases', + displayName: 'Nombre de visualización de Base', + importFromTemplate: 'Importar desde plantilla', + createBase: 'Crear Base', + baseSettings: 'Configuración de Base', + updateBase: 'Actualizar Base', + deleteBase: 'Eliminar Base', + updateBaseName: 'Actualizar nombre de Base', + deleteBaseConfirm: '¿Desea eliminar Base?', + duplicateBase: 'Duplicar Base {name}', + includeData: 'Incluir datos', + nameDescription: 'Nombre de visualización de Base.', + includeDataDescription: 'Incluir datos en la nueva Base.', + duplicateBaseDescription: 'Crear una nueva Base y incluir todos los registros de la Base.', + systemFieldsUpdated: 'Los campos del sistema se actualizarán con la fecha y hora del usuario actual.' +} + +const space = { + spaces: 'Espacios', + name: 'Nombre del espacio', + setDisplayName: 'Establecer nombre de visualización', + searchMembers: 'Buscar miembros...', + cannotInviteMemberToPersonalSpace: 'No se puede invitar a miembros a un espacio personal.', + createSpace: 'Crear espacio', + createSpaceDescription: 'Crear un nuevo espacio y organizar datos y colaborar con otros miembros del equipo.', + spaceName: 'Nombre del espacio', + spaceNameDescription: 'Nombre de visualización del espacio.', + personalSpace: 'No se puede eliminar un espacio personal.', + deleteSpace: 'Eliminar espacio', + deleteSpaceConfirm: '¿Desea eliminar el espacio?', + deleteSpaceDescription: 'Esta operación no se puede cancelar. Esta operación eliminará permanentemente el estado de la base de datos y eliminará los datos del servidor.', + memberList: 'Lista de miembros del área de trabajo', + inviteMember: 'Invitar miembro', + invitations: 'Invitaciones', + invite: 'Invitar', + pendingInvitations: 'Lista de invitaciones pendientes', + invitedAt: 'Invitado en', + deleteInvitation: 'Eliminar invitación' +} + +const schema = { + label: 'Estructura de campo', + systemFields: 'Campos del sistema', + required: 'Requerido', + display: 'Mostrar', + fieldName: 'Nombre del campo', + addField: 'Agregar campo' +} + +const account = { + logout: 'Cerrar sesión', + accountSettings: 'Configuración de cuenta', + apiToken: 'Token de API', + undbTemplates: 'Plantillas de Undb', + undbWebsite: 'Sitio web de Undb' +} + +const setting = { + setting: 'Configuración', + members: 'Miembros', + settingAndMembers: 'Configuración y miembros' +} + +const roles = { + owner: 'Propietario', + admin: 'Administrador', + member: 'Miembro', + viewer: 'Visor' +} + +const webhook = { + label: 'Webhook', + create: 'Crear Webhook', + delete: 'Eliminar Webhook', + update: 'Actualizar Webhook', + duplicate: 'Duplicar Webhook', + noWebhooks: '{table} no hay Webhooks', + noWebhooksDescription: 'Haga clic en el botón para crear el primer Webhook' +} + +const authz = { + noRecordLevelSecurity: '{table} no hay permisos de nivel de registro', + noRecordLevelSecurityDescription: 'Haga clic en el botón para crear la estrategia de permisos de nivel de registro', + create: 'Crear permisos de nivel de registro', + created: 'Permisos de nivel de registro creados', + failed: 'Error al crear permisos de nivel de registro', + rlsName: 'Nombre de permisos de nivel de registro', + giveYourRLSName: 'Déjame tu nombre de permisos de nivel de registro', + actions: { + read: 'Leer', + create: 'Crear', + update: 'Actualizar', + delete: 'Eliminar' + }, + subjectName: 'Sujeto', + subject: { + any: 'Todos los usuarios', + user: 'Usuario especificado', + group: 'Grupo de usuario especificado' + }, + action: 'Acción', + allow: 'Permitir', + deny: 'Denegar', + matchesConditions: 'Condiciones coincidentes...', + updateCondition: 'Actualizar condición', + notAllow: 'No permitir', + updateRLS: 'Actualizar permisos de nivel de registro', + policy: { + update: 'Estrategia de actualización', + delete: 'Estrategia de eliminación' + } +} + +const events = { + record: { + created: 'Registro creado', + updated: 'Registro actualizado', + deleted: 'Registro eliminado' + } +} + +const template = { + createBase: 'Crear Base', + selectATemplateToCreateABase: 'Selecciona una plantilla para crear una Base' +} + +const auth = { + login: 'Iniciar sesión', + loginFailed: 'Inicio de sesión fallido', + forgotPassword: '¿Olvidaste tu contraseña?', + emailPlaceholder: 'Introduce tu correo electrónico para iniciar sesión...', + password: 'Contraseña', + register: 'Registrarse', + noAccount: '¿No tienes una cuenta?', + registerDisabled: 'El registro está deshabilitado.', + registerDisabledDescription: 'Póngase en contacto con su administrador para solicitar acceso.', + loginWith: 'Iniciar sesión con {provider}', + invalidEmailOrPassword: 'Correo electrónico o contraseña inválidos.', + loginToYourAccountAndAcceptTheInvitation: 'Iniciar sesión en su cuenta y aceptar la invitación', + enterYourEmailBelowToResetYourPassword: 'Introduce tu correo electrónico a continuación para restablecer tu contraseña.', + emailSent: '¡Correo electrónico enviado!', + youCanCheckYourEmailAddressAndFollowTheStepsToResetYourPassword: 'Puedes comprobar tu correo electrónico y seguir los pasos para restablecer tu contraseña.', + registerFailed: 'Registro fallido', + passwordDoesNotMatch: 'Contraseña no coincide', + enterYourDisplayUsername: 'Introduce tu nombre de usuario para mostrar', + username: 'Nombre de usuario', + invited: 'Invitado', + confirmPassword: 'Confirmar contraseña', + createAnAccount: 'Crear una cuenta', + alreadyHaveAnAccount: '¿Ya tienes una cuenta?', + enterYourWorkEmail: 'Introduce tu correo electrónico de trabajo...', +} + +const es = { + auth, + template, + roles, + setting, + base, + space, + account, + table: { + ops, + fieldTypes, + rollupFns, + aggregateFns, + macros, + viewTypes, + widgetTypes, + timeScales, + record, + form, + common, + field, + view, + aggregate, + schema, + authz, + events, + }, + webhook, + common: { + error: 'Error', + continue: 'Continuar', + description: 'Descripción', + cancel: 'Cancelar', + create: 'Crear', + search: 'Buscar', + creating: 'Creando', + confirm: 'Confirmar', + update: 'Actualizar', + select: 'Seleccionar', + event: 'Evento', + submit: 'Enviar', + duplicate: 'Duplicar', + delete: 'Eliminar', + settings: 'Configuración', + save: 'Guardar', + language: 'Idioma', + data: 'Datos', + auth: 'Permisos', + developer: 'Desarrollador', + name: 'Nombre', + dangerZone: 'Zona de peligro', + remove: 'Eliminar', + accountAndSpaceSettings: 'Configuración de cuenta y espacio', + email: 'Correo electrónico', + role: 'Rol', + action: 'Acción', + status: 'Estado', + required: 'Requerido', + enabled: 'Habilitado', + enableCondition: 'Condición de habilitación', + type: 'Tipo', + loadMore: 'Cargar más', + today: 'Hoy', + clear: 'Limpiar', + updated: 'Actualizado', + }, + share: { + title: 'Compartir', + shareUrl: 'Enlace de compartido', + iframeUrl: 'Enlace de inserción', + shareId: 'ID de compartido', + enable: 'Habilitar compartido', + copied: 'Copiado al portapapeles', + button: 'Compartir' +}, +widget: { + title: 'Widget', + button: "Widget", + name: 'Nombre', + add: 'Agregar widget', + editName: 'Editar nombre', + duplicate: 'Duplicar widget {name}', + delete: 'Eliminar widget {name}', + deleteConfirm: { + title: '¿Eliminar widget {name}?', + description: 'Esta operación no se puede cancelar. Esta operación eliminará permanentemente este widget y eliminará los datos del servidor.' + }, + count: 'Cantidad', + aggregate: 'Agregado', + filters: 'Filtros', +}, +dashboard + +} satisfies BaseTranslation + +export default es \ No newline at end of file diff --git a/packages/i18n/src/i18n/i18n-types.ts b/packages/i18n/src/i18n/i18n-types.ts index 8f41dfb46..4421e7540 100644 --- a/packages/i18n/src/i18n/i18n-types.ts +++ b/packages/i18n/src/i18n/i18n-types.ts @@ -9,6 +9,7 @@ export type Locales = | 'ja' | 'zh' | 'ko' + | 'es' | 'en' export type Translation = RootTranslation @@ -16,6 +17,127 @@ export type Translation = RootTranslation export type Translations = RootTranslation type RootTranslation = { + auth: { + /** + * L​o​g​i​n + */ + login: string + /** + * L​o​g​i​n​ ​f​a​i​l​e​d + */ + loginFailed: string + /** + * F​o​r​g​o​t​ ​y​o​u​r​ ​p​a​s​s​w​o​r​d​? + */ + forgotPassword: string + /** + * E​n​t​e​r​ ​y​o​u​r​ ​e​m​a​i​l​ ​t​o​ ​l​o​g​i​n + */ + emailPlaceholder: string + /** + * P​a​s​s​w​o​r​d + */ + password: string + /** + * R​e​g​i​s​t​e​r + */ + register: string + /** + * D​o​n​'​t​ ​h​a​v​e​ ​a​n​ ​a​c​c​o​u​n​t​? + */ + noAccount: string + /** + * R​e​g​i​s​t​r​a​t​i​o​n​ ​i​s​ ​d​i​s​a​b​l​e​d​. + */ + registerDisabled: string + /** + * C​o​n​t​a​c​t​ ​y​o​u​r​ ​a​d​m​i​n​i​s​t​r​a​t​o​r​ ​t​o​ ​r​e​q​u​e​s​t​ ​a​c​c​e​s​s​. + */ + registerDisabledDescription: string + /** + * L​o​g​i​n​ ​w​i​t​h​ ​{​p​r​o​v​i​d​e​r​} + * @param {unknown} provider + */ + loginWith: RequiredParams<'provider'> + /** + * I​n​v​a​l​i​d​ ​e​m​a​i​l​ ​o​r​ ​p​a​s​s​w​o​r​d​. + */ + invalidEmailOrPassword: string + /** + * L​o​g​i​n​ ​t​o​ ​y​o​u​r​ ​a​c​c​o​u​n​t​ ​a​n​d​ ​a​c​c​e​p​t​ ​t​h​e​ ​i​n​v​i​t​a​t​i​o​n + */ + loginToYourAccountAndAcceptTheInvitation: string + /** + * E​n​t​e​r​ ​y​o​u​r​ ​e​m​a​i​l​ ​b​e​l​o​w​ ​t​o​ ​r​e​s​e​t​ ​y​o​u​r​ ​p​a​s​s​w​o​r​d​. + */ + enterYourEmailBelowToResetYourPassword: string + /** + * E​m​a​i​l​ ​s​e​n​t​! + */ + emailSent: string + /** + * Y​o​u​ ​c​a​n​ ​c​h​e​c​k​ ​y​o​u​r​ ​e​m​a​i​l​ ​a​d​d​r​e​s​s​ ​a​n​d​ ​f​o​l​l​o​w​ ​t​h​e​ ​s​t​e​p​s​ ​t​o​ ​r​e​s​e​t​ ​y​o​u​r​ ​p​a​s​s​w​o​r​d​. + */ + youCanCheckYourEmailAddressAndFollowTheStepsToResetYourPassword: string + /** + * R​e​g​i​s​t​e​r​ ​f​a​i​l​e​d + */ + registerFailed: string + /** + * P​a​s​s​w​o​r​d​ ​d​o​e​s​ ​n​o​t​ ​m​a​t​c​h + */ + passwordDoesNotMatch: string + /** + * E​n​t​e​r​ ​y​o​u​r​ ​d​i​s​p​l​a​y​ ​u​s​e​r​n​a​m​e + */ + enterYourDisplayUsername: string + /** + * U​s​e​r​n​a​m​e + */ + username: string + /** + * I​n​v​i​t​e​d + */ + invited: string + /** + * C​o​n​f​i​r​m​ ​p​a​s​s​w​o​r​d + */ + confirmPassword: string + /** + * C​r​e​a​t​e​ ​a​n​ ​a​c​c​o​u​n​t + */ + createAnAccount: string + /** + * A​l​r​e​a​d​y​ ​h​a​v​e​ ​a​n​ ​a​c​c​o​u​n​t​? + */ + alreadyHaveAnAccount: string + /** + * S​i​g​n​ ​i​n + */ + signIn: string + /** + * C​r​e​a​t​e​ ​a​c​c​o​u​n​t​ ​a​n​d​ ​a​c​c​e​p​t​ ​i​n​v​i​t​a​t​i​o​n + */ + createAccountAndAcceptInvitation: string + /** + * E​n​t​e​r​ ​y​o​u​r​ ​i​n​f​o​r​m​a​t​i​o​n​ ​t​o​ ​c​r​e​a​t​e​ ​a​n​ ​a​c​c​o​u​n​t​. + */ + enterYourInformationToCreateAnAccount: string + /** + * E​n​t​e​r​ ​y​o​u​r​ ​w​o​r​k​ ​e​m​a​i​l​.​.​. + */ + enterYourWorkEmail: string + } + template: { + /** + * C​r​e​a​t​e​ ​N​e​w​ ​B​a​s​e + */ + createBase: string + /** + * S​e​l​e​c​t​ ​a​ ​t​e​m​p​l​a​t​e​ ​t​o​ ​c​r​e​a​t​e​ ​a​ ​n​e​w​ ​b​a​s​e + */ + selectATemplateToCreateABase: string + } setting: { /** * S​e​t​t​i​n​g​s @@ -1991,6 +2113,10 @@ type RootTranslation = { } } common: { + /** + * E​r​r​o​r + */ + error: string /** * D​u​p​l​i​c​a​t​e */ @@ -2270,6 +2396,126 @@ type RootTranslation = { } export type TranslationFunctions = { + auth: { + /** + * Login + */ + login: () => LocalizedString + /** + * Login failed + */ + loginFailed: () => LocalizedString + /** + * Forgot your password? + */ + forgotPassword: () => LocalizedString + /** + * Enter your email to login + */ + emailPlaceholder: () => LocalizedString + /** + * Password + */ + password: () => LocalizedString + /** + * Register + */ + register: () => LocalizedString + /** + * Don't have an account? + */ + noAccount: () => LocalizedString + /** + * Registration is disabled. + */ + registerDisabled: () => LocalizedString + /** + * Contact your administrator to request access. + */ + registerDisabledDescription: () => LocalizedString + /** + * Login with {provider} + */ + loginWith: (arg: { provider: unknown }) => LocalizedString + /** + * Invalid email or password. + */ + invalidEmailOrPassword: () => LocalizedString + /** + * Login to your account and accept the invitation + */ + loginToYourAccountAndAcceptTheInvitation: () => LocalizedString + /** + * Enter your email below to reset your password. + */ + enterYourEmailBelowToResetYourPassword: () => LocalizedString + /** + * Email sent! + */ + emailSent: () => LocalizedString + /** + * You can check your email address and follow the steps to reset your password. + */ + youCanCheckYourEmailAddressAndFollowTheStepsToResetYourPassword: () => LocalizedString + /** + * Register failed + */ + registerFailed: () => LocalizedString + /** + * Password does not match + */ + passwordDoesNotMatch: () => LocalizedString + /** + * Enter your display username + */ + enterYourDisplayUsername: () => LocalizedString + /** + * Username + */ + username: () => LocalizedString + /** + * Invited + */ + invited: () => LocalizedString + /** + * Confirm password + */ + confirmPassword: () => LocalizedString + /** + * Create an account + */ + createAnAccount: () => LocalizedString + /** + * Already have an account? + */ + alreadyHaveAnAccount: () => LocalizedString + /** + * Sign in + */ + signIn: () => LocalizedString + /** + * Create account and accept invitation + */ + createAccountAndAcceptInvitation: () => LocalizedString + /** + * Enter your information to create an account. + */ + enterYourInformationToCreateAnAccount: () => LocalizedString + /** + * Enter your work email... + */ + enterYourWorkEmail: () => LocalizedString + } + template: { + /** + * Create New Base + */ + createBase: () => LocalizedString + /** + * Select a template to create a new base + */ + selectATemplateToCreateABase: () => LocalizedString + } setting: { /** * Settings @@ -4219,6 +4465,10 @@ export type TranslationFunctions = { } } common: { + /** + * Error + */ + error: () => LocalizedString /** * Duplicate */ diff --git a/packages/i18n/src/i18n/i18n-util.async.ts b/packages/i18n/src/i18n/i18n-util.async.ts index c77f8da0a..5b5766809 100644 --- a/packages/i18n/src/i18n/i18n-util.async.ts +++ b/packages/i18n/src/i18n/i18n-util.async.ts @@ -9,6 +9,7 @@ const localeTranslationLoaders = { ja: () => import('./ja/index.js'), zh: () => import('./zh/index.js'), ko: () => import('./ko/index.js'), + es: () => import('./es/index.js'), en: () => import('./en/index.js'), } diff --git a/packages/i18n/src/i18n/i18n-util.sync.ts b/packages/i18n/src/i18n/i18n-util.sync.ts index 310ff5134..629273645 100644 --- a/packages/i18n/src/i18n/i18n-util.sync.ts +++ b/packages/i18n/src/i18n/i18n-util.sync.ts @@ -8,12 +8,14 @@ import { loadedFormatters, loadedLocales, locales } from './i18n-util.js' import ja from './ja/index.js' import zh from './zh/index.js' import ko from './ko/index.js' +import es from './es/index.js' import en from './en/index.js' const localeTranslations = { ja, zh, ko, + es, en, } diff --git a/packages/i18n/src/i18n/i18n-util.ts b/packages/i18n/src/i18n/i18n-util.ts index 3c551981a..5c16b978e 100644 --- a/packages/i18n/src/i18n/i18n-util.ts +++ b/packages/i18n/src/i18n/i18n-util.ts @@ -14,6 +14,7 @@ export const locales: Locales[] = [ 'ja', 'zh', 'ko', + 'es', 'en' ] diff --git a/packages/i18n/src/i18n/ja/index.ts b/packages/i18n/src/i18n/ja/index.ts index 877812c5c..08e2f0121 100644 --- a/packages/i18n/src/i18n/ja/index.ts +++ b/packages/i18n/src/i18n/ja/index.ts @@ -622,7 +622,38 @@ const template = { selectATemplateToCreateABase: 'テンプレートを選択して Base を作成します' } -const zh = { +const auth = { + login: 'ログイン', + loginFailed: 'ログインに失敗しました', + forgotPassword: 'パスワードを忘れましたか?', + emailPlaceholder: 'メールアドレスを入力してください...', + password: 'パスワード', + register: '登録', + noAccount: 'アカウントがありませんか?', + registerDisabled: '登録が無効になっています。', + loginWith: 'ログイン {provider}', + invalidEmailOrPassword: '無効なメールアドレスまたはパスワードです。', + loginToYourAccountAndAcceptTheInvitation: 'ログインして招待を受け入れます', + resetPassword: 'パスワードをリセット', + enterYourEmailBelowToResetYourPassword: 'パスワードをリセットするためにメールアドレスを入力してください。', + emailSent: 'メールが送信されました!', + youCanCheckYourEmailAddressAndFollowTheStepsToResetYourPassword: 'メールアドレスを確認して、パスワードをリセットする手順を実行してください。', + registerFailed: '登録に失敗しました', + passwordDoesNotMatch: 'パスワードが一致しません', + enterYourDisplayUsername: '表示ユーザー名を入力してください', + username: 'ユーザー名', + invited: '招待済み', + confirmPassword: 'パスワードを確認', + createAnAccount: 'アカウントを作成', + alreadyHaveAnAccount: 'アカウントがありますか?', + signIn: 'ログイン', + createAccountAndAcceptInvitation: 'アカウントを作成して招待を受け入れる', + enterYourInformationToCreateAnAccount: 'アカウントを作成するための情報を入力してください。', + enterYourWorkEmail: '作業用メールアドレスを入力してください...', +} + +const ja = { + auth, template, roles, setting, @@ -650,6 +681,7 @@ const zh = { }, webhook, common: { + error: 'エラー', continue: '続行', description: '説明', cancel: 'キャンセル', @@ -715,4 +747,4 @@ dashboard } satisfies BaseTranslation -export default zh \ No newline at end of file +export default ja \ No newline at end of file diff --git a/packages/i18n/src/i18n/ko/index.ts b/packages/i18n/src/i18n/ko/index.ts index a196e9b78..44924aba4 100644 --- a/packages/i18n/src/i18n/ko/index.ts +++ b/packages/i18n/src/i18n/ko/index.ts @@ -622,7 +622,38 @@ const template = { selectATemplateToCreateABase: '템플릿을 선택하여 Base를 생성하세요' } +const auth = { + login: '로그인', + loginFailed: '로그인 실패', + forgotPassword: '비밀번호를 까먹었나요?', + emailPlaceholder: '이메일 주소를 입력하세요...', + password: '비밀번호', + register: '회원가입', + noAccount: '계정이 없나요?', + registerDisabled: '회원가입이 비활성화되었습니다.', + registerDisabledDescription: '관리자에게 문의하여 회원가입을 요청하세요.', + loginWith: '로그인 {provider}', + invalidEmailOrPassword: '유효하지 않은 이메일 또는 비밀번호입니다.', + loginToYourAccountAndAcceptTheInvitation: '로그인하여 초대를 수락하세요', + enterYourEmailBelowToResetYourPassword: '비밀번호를 재설정하기 위해 이메일 주소를 입력하세요.', + emailSent: '이메일이 전송되었습니다!', + youCanCheckYourEmailAddressAndFollowTheStepsToResetYourPassword: '이메일 주소를 확인하고 비밀번호를 재설정하는 단계를 따르세요.', + registerFailed: '회원가입 실패', + passwordDoesNotMatch: '비밀번호가 일치하지 않습니다', + enterYourDisplayUsername: '표시 사용자 이름을 입력하세요', + username: '사용자 이름', + invited: '초대됨', + confirmPassword: '비밀번호 확인', + createAnAccount: '계정 생성', + alreadyHaveAnAccount: '계정이 있나요?', + signIn: '로그인', + createAccountAndAcceptInvitation: '계정 생성 및 초대 수락', + enterYourInformationToCreateAnAccount: '계정을 생성하기 위한 정보를 입력하세요.', + enterYourWorkEmail: '작업 이메일을 입력하세요...', +} + const ko = { + auth, template, roles, setting, @@ -650,6 +681,7 @@ const ko = { }, webhook, common: { + error: '오류', continue: '계속', description: '설명', cancel: '취소', diff --git a/packages/i18n/src/i18n/zh/index.ts b/packages/i18n/src/i18n/zh/index.ts index 4300df7c1..e618a8864 100644 --- a/packages/i18n/src/i18n/zh/index.ts +++ b/packages/i18n/src/i18n/zh/index.ts @@ -622,7 +622,40 @@ const template= { selectATemplateToCreateABase: '选择一个模板来创建一个 Base' } +const auth = { + login: '登录', + loginFailed: '登录失败', + forgotPassword: '忘记密码?', + emailPlaceholder: '输入您的电子邮件地址...', + password: '密码', + register: '注册', + noAccount: '没有账户?', + registerDisabled: '注册已禁用', + loginWithEmailDescription: '输入您的电子邮件地址和密码登录。', + registerDisabledDescription: '请联系管理员启用注册。', + loginWith: '使用 {provider} 登录', + invalidEmailOrPassword: '无效的电子邮件或密码。', + loginToYourAccountAndAcceptTheInvitation: '登录到您的账户并接受邀请', + resetPassword: '重置密码', + enterYourEmailBelowToResetYourPassword: '输入您的电子邮件地址以重置您的密码。', + emailSent: '电子邮件已发送!', + youCanCheckYourEmailAddressAndFollowTheStepsToResetYourPassword: '您可以检查您的电子邮件地址并按照步骤重置您的密码。', + registerFailed: '注册失败', + passwordDoesNotMatch: '密码不匹配', + enterYourDisplayUsername: '输入您的显示用户名', + username: '用户名', + invited: '已邀请', + confirmPassword: '确认密码', + createAnAccount: '创建一个账户', + alreadyHaveAnAccount: '已经有账户?', + signIn: '登录', + createAccountAndAcceptInvitation: '创建账户并接受邀请', + enterYourInformationToCreateAnAccount: '输入您的信息以创建一个账户。', + enterYourWorkEmail: '输入您的工作电子邮件...', +} + const zh = { + auth, template, roles, setting, @@ -650,6 +683,7 @@ const zh = { }, webhook, common: { + error: '错误', continue: '继续', description: '描述', cancel: '取消',