Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Required translation updates for Spanish #1028

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions docs/basics/validation.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,63 @@ Los validadores también pueden combinarse mediante operadores para construir va
|`!`|prefijo|Invierte un validador, requiriendo lo opuesto.|
|`&&`|infijo|Combina dos validadores, requiere ambos.|
|`||`|infijo|Combina dos validadores, requiere al menos uno.|

## Validadores Personalizados

Crear un validador personalizado para códigos postales te permite extender la funcionalidad del marco de validación. En esta sección, te guiaremos a través de los pasos para crear un validador personalizado que valide códigos postales.

Primero, crea un nuevo tipo para representar los resultados de la validación de `ZipCode`. Esta estructura será responsable de informar si una cadena dada es un código postal válido.

```swift
extension ValidatorResults {
/// Representa el resultado de un validador que verifica si una cadena es un código postal válido.
public struct ZipCode {
/// Indica si la entrada es un código postal válido.
public let isValidZipCode: Bool
}
}
```

A continuación, haz que el nuevo tipo cumpla con `ValidatorResult`, que define el comportamiento esperado de un validador personalizado.

```swift
extension ValidatorResults.ZipCode: ValidatorResult {
public var isFailure: Bool {
!self.isValidZipCode
}

public var successDescription: String? {
"is a valid zip code"
}

public var failureDescription: String? {
"is not a valid zip code"
}
}
```

Finalmente, implementa la lógica de validación para los códigos postales. Usa una expresión regular para verificar si la cadena de entrada coincide con el formato de un código postal de EE.UU.

```swift
private let zipCodeRegex: String = "^\\d{5}(?:[-\\s]\\d{4})?$"

extension Validator where T == String {
/// Valida si una cadena es un código postal válido.
public static var zipCode: Validator<T> {
.init { input in
guard let range = input.range(of: zipCodeRegex, options: [.regularExpression]),
range.lowerBound == input.startIndex && range.upperBound == input.endIndex
else {
return ValidatorResults.ZipCode(isValidZipCode: false)
}
return ValidatorResults.ZipCode(isValidZipCode: true)
}
}
}
```

Ahora que has definido el validador personalizado `zipCode`, puedes usarlo para validar códigos postales en tu aplicación. Simplemente agrega la siguiente línea a tu código de validación:

```swift
validations.add("zipCode", as: String.self, is: .zipCode)
```
12 changes: 7 additions & 5 deletions docs/fluent/model.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,12 +359,14 @@ app.get("planets") { req async throws in

Al serializar desde/hacia `Codable`, las propiedades del modelo usarán sus nombres de variable en lugar de las claves. Las relaciones serán serializadas como estructuras anidadas y cualquier carga previa (eager loading) de datos será incluida.

alemohamad marked this conversation as resolved.
Show resolved Hide resolved
!!! info "Información"
Recomendamos que para casi todos los casos utilices un DTO en lugar de un modelo para tus respuestas de API y los cuerpos de tus solicitudes. Consulta [Objeto de transferencia de datos](#data-transfer-object) para obtener más información.

### Data Transfer Object

La conformidad por defecto del modelo a `Codable` puede facilitar el prototipado y usos simples. Sin embargo, no se ajusta a todos los casos de uso. Para ciertas situaciones necesitarás usar un data transfer object (DTO).
La conformidad por defecto del modelo a `Codable` puede facilitar el prototipado y usos simples. Sin embargo, expone la información subyacente de la base de datos a la API. Esto generalmente no es deseable desde un punto de vista de seguridad —devolver campos sensibles como el hash de la contraseña de un usuario es una mala idea— y desde una perspectiva de usabilidad. Hace difícil cambiar el esquema de la base de datos sin romper la API, aceptar o devolver datos en un formato diferente, o agregar o eliminar campos de la API.
alemohamad marked this conversation as resolved.
Show resolved Hide resolved

!!! tip "Consejo"
Un DTO es un tipo `Codable` aparte que representa la estructura de datos que quieres codificar/descodificar.
En la mayoría de los casos, deberías usar un DTO o data transfer object (objeto de transferencia de datos) en lugar de un modelo (también conocido como domain transfer object). Un DTO es un tipo `Codable` separado que representa la estructura de datos que deseas codificar o decodificar. Esto desacopla tu API del esquema de la base de datos y te permite realizar cambios en tus modelos sin romper la API pública de tu aplicación, tener diferentes versiones y hacer que tu API sea más agradable de usar para tus clientes.

Toma como base el siguiente modelo de `User` para los ejemplos a continuación.

Expand Down Expand Up @@ -434,9 +436,9 @@ app.get("users") { req async throws -> [GetUser] in
}
```

Aunque la estructura del DTO sea idéntica a la del modelo conformado con `Codable`, tenerlo como tipo aparte puede ayudar a mantener los proyectos grandes ordenados. Si necesitaras hacer un cambio en las propiedades de tu modelo, no tienes que preocuparte de si rompes la API pública de tu app. Puedes considerar agrupar tus DTO en un package aparte que puedas compartir con los consumidores de tu API.
Otro caso de uso común es al trabajar con relaciones, como relaciones de padre o de hijos. Consulta [la documentación de Parent](relations.es.md#codificación-y-decodificación-de-relaciones-parent) para ver un ejemplo de cómo usar un DTO para facilitar la decodificación de un modelo con una relación `@Parent`.

Por estas razones, recomendamos encarecidamente usar DTO siempre que sea posible, especialmente en proyectos grandes.
Incluso si la estructura del DTO es idéntica a la conformidad `Codable` del modelo, tenerlo como un tipo separado puede ayudar a mantener organizados los proyectos grandes. Si alguna vez necesitas realizar un cambio en las propiedades de tus modelos, no tendrás que preocuparte por romper la API pública de tu aplicación. También puedes considerar colocar tus DTOs en un paquete separado que pueda ser compartido con los consumidores de tu API y agregar conformidad a `Content` en tu aplicación Vapor.

## Alias

Expand Down
49 changes: 45 additions & 4 deletions docs/fluent/relations.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,39 @@ La definición del campo es similar a la de `@Parent`, excepto la constraint `.r
.field("star_id", .uuid, .references("star", "id"))
```

### Codificación y Decodificación de Relaciones Parent

Algo a tener en cuenta al trabajar con relaciones `@Parent` es la forma en que se envían y reciben. Por ejemplo, en JSON, una relación `@Parent` para un modelo `Planet` podría verse así:

```json
{
"id": "A616B398-A963-4EC7-9D1D-B1AA8A6F1107",
"star": {
"id": "A1B2C3D4-1234-5678-90AB-CDEF12345678"
}
}
```

Nota cómo la propiedad `star` es un objeto en lugar del ID que podrías esperar. Al enviar el modelo como un cuerpo HTTP, debe coincidir con esta estructura para que la decodificación funcione. Por esta razón, recomendamos encarecidamente usar un DTO para representar el modelo al enviarlo por la red. Por ejemplo:

```swift
struct PlanetDTO: Content {
var id: UUID?
var name: String
var star: Star.IDValue
}
```

Luego puedes decodificar el DTO y convertirlo en un modelo:

```swift
let planetData = try req.content.decode(PlanetDTO.self)
let planet = Planet(id: planetData.id, name: planetData.name, starID: planetData.star)
try await planet.create(on: req.db)
```

Lo mismo aplica al devolver el modelo a los clientes. Tus clientes deben poder manejar la estructura anidada o necesitas convertir el modelo en un DTO antes de devolverlo. Para más información sobre los DTOs, consulta la [documentación del modelo](model.es.md#data-transfer-object).

## Optional Child

La propiedad `@OptionalChild` crea una relación uno a uno entre dos modelos. No guarda ningún valor en el modelo raíz.
Expand Down Expand Up @@ -284,7 +317,7 @@ Ver [query](query.md) para más información.

## Eager Loading

El constructor de consultas (query builder) de Fluent te permite precargar las relaciones de un modelo cuando es recuperado de la base de datos. Esto se conoce como "eager loading" y te permite acceder a las relaciones de manera sincrónica sin la necesidad de llamar previamente a [`load`](#lazy-eager-loading) o [`get`](#get) .
El constructor de consultas (query builder) de Fluent te permite precargar las relaciones de un modelo cuando es recuperado de la base de datos. Esto se conoce como "eager loading" y te permite acceder a las relaciones de manera sincrónica sin la necesidad de llamar a [`get`](#get) primero.

Para hacer un "eager load" de una relación, pasa un key path a la relación con el método `with` en el constructor de consultas.

Expand All @@ -311,6 +344,7 @@ for planet in planets {
En el ejemplo anterior, se le ha pasado un key path a la relación [`@Parent`](#parent) llamada `star` con `with`. Esto provoca que el constructor de consultas haga una consulta adicional después de cargar todos los planetas para recuperar todas las estrellas conectadas a éstos. Las estrellas son accesibles de manera sincrónica mediante la propiedad `@Parent`.

Cada relación precargada (eager loaded) necesita una única consulta adicional, sin importar cuántos modelos se hayan devuelto. La precarga (eager loading) sólo es posible con los métodos de constructor de consultas `all` y `first`.

### Nested Eager Load

El método de constructor de consultas `with` te permite precargar relaciones en el modelo que está siendo consultado. Sin embargo, también puedes precargar relaciones en los modelos conectados.
Expand All @@ -330,16 +364,23 @@ El método `with` acepta un closure opcional como segundo parámetro. Este closu

## Lazy Eager Loading

En caso de que ya hayas recuperado el modelo del parent y quieres cargar una de sus relaciones, puedes usar el método `load(on:)` para hacerlo. Esto recuperará el modelo conectado de la base de datos y permitirá acceder a él como una propiedad local.
En caso de que ya hayas recuperado el modelo del parent y quieres cargar una de sus relaciones, puedes usar el método `get(reload:on:)` para hacerlo. Esto recuperará el modelo conectado de la base de datos (o de la caché, si está disponible) y permitirá acceder a él como una propiedad local.

```swift
planet.$star.load(on: database).map {
planet.$star.get(on: database).map {
print(planet.star.name)
}

// O

try await planet.$star.load(on: database)
try await planet.$star.get(on: database)
print(planet.star.name)
```

En caso de que quieras asegurarte de que los datos que recibes no se obtienen desde la caché, utiliza el parámetro `reload:`.

```swift
try await planet.$star.get(reload: true, on: database)
print(planet.star.name)
```

Expand Down
25 changes: 22 additions & 3 deletions docs/fluent/schema.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,15 +380,34 @@ Podemos hacer los ajustes necesarios del esquema de la base de datos con la sigu
```swift
struct UserNameMigration: AsyncMigration {
func prepare(on database: Database) async throws {
try await database.schema("users")
.field("first_name", .string, .required)
.field("last_name", .string, .required)
.update()

// Actualmente no es posible expresar esta actualización sin usar SQL personalizado.
// Esto tampoco intenta dividir el nombre en nombre y apellido,
// ya que eso requiere sintaxis específica de la base de datos.
try await User.query(on: database)
.set(["first_name": .sql(embed: "name"))
.run()

try await database.schema("users")
.deleteField("name")
.field("first_name", .string)
.field("last_name", .string)
.update()
}

func revert(on database: Database) async throws {
try await database.schema("users").delete()
try await database.schema("users")
.field("name", .string, .required)
.update()
try await User.query(on: database)
.set(["name": .sql(embed: "concat(first_name, ' ', last_name)"))
.run()
try await database.schema("users")
.deleteField("first_name")
.deleteField("last_name")
.update()
}
}
```
Expand Down
39 changes: 26 additions & 13 deletions docs/install/linux.es.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
# Instalación en Linux

Para usar Vapor, necesitas Swift 5.9 o superior. Se puede instalar usando las opciones disponibles en [Swift.org](https://swift.org/download/).
Para usar Vapor, necesitas Swift 5.9 o superior. Esto se puede instalar utilizando la herramienta CLI [Swiftly](https://swiftlang.github.io/swiftly/) proporcionada por el Swift Server Workgroup (recomendado), o las toolchains disponibles en [Swift.org](https://swift.org/download/).

## Distribuciones y Versiones Soportadas

Vapor admite las mismas versiones de distribución de Linux que adminte Swift 5.9 o versiones más recientes.

!!! nota
Las versiones soportadas que se enumeran a continuación pueden quedar obsoletas en cualquier momento. Puedes comprobar qué sistemas operativos son oficialmente compatibles en la página [Swift Releases](https://swift.org/download/#releases).

|Distribución|Versión|Versión de Swift|
|-|-|-|
|Ubuntu|20.04|>= 5.9|
|Fedora|>= 30|>= 5.9|
|CentOS|8|>= 5.9|
|Amazon Linux|2|>= 5.9|
Vapor es compatible con las mismas versiones de distribuciones de Linux que soportan Swift 5.9 o versiones posteriores. Por favor, consulta la [página oficial de soporte](https://www.swift.org/platform-support/) para obtener información actualizada sobre los sistemas operativos oficialmente compatibles.

Las distribuciones de Linux que no son oficialmente compatibles también pueden ejecutar Swift al compilar el código fuente, pero Vapor no puede garantizar estabilidad. Puedes aprender más sobre cómo compilar Swift desde [Swift Repo](https://github.com/apple/swift#getting-started).

## Instalar Swift

### Instalación automatizada usando la herramienta Swiftly CLI (recomendada)

Visita el [sitio web de Swiftly](https://swiftlang.github.io/swiftly/) para obtener instrucciones sobre cómo instalar Swiftly y Swift en Linux. Después de eso, instala Swift con el siguiente comando:

#### Uso básico

```sh
$ swiftly install latest

Fetching the latest stable Swift release...
Installing Swift 5.9.1
Downloaded 488.5 MiB of 488.5 MiB
Extracting toolchain...
Swift 5.9.1 installed successfully!

$ swift --version

Swift version 5.9.1 (swift-5.9.1-RELEASE)
Target: x86_64-unknown-linux-gnu
```

### Instalación manual con la toolchain

Visita la guía [Using Downloads](https://swift.org/download/#using-downloads) de Swift.org para ver las instrucciones de cómo instalar Swift en Linux.

### Fedora
Expand All @@ -30,7 +43,7 @@ Los usuarios de Fedora pueden simplemente utilizar el siguiente comando para ins
sudo dnf install swift-lang
```

Si utilizas Fedora 30, deberás agregar EPEL 8 para obtener Swift 5.9 o versiones más nuevas.
Si utilizas Fedora 35, deberás agregar EPEL 8 para obtener Swift 5.9 o versiones más nuevas.

## Docker

Expand Down
4 changes: 2 additions & 2 deletions docs/leaf/getting-started.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Leaf es un potente lenguaje de plantillas con una sintaxis inspirada en Swift. P
El primer paso para usar Leaf es agregarlo como una dependencia en tu proyecto en tu archivo de manifiesto del paquete SPM.

```swift
// swift-tools-version:5.2
// swift-tools-version:5.9
alemohamad marked this conversation as resolved.
Show resolved Hide resolved
import PackageDescription

let package = Package(
Expand All @@ -17,7 +17,7 @@ let package = Package(
],
dependencies: [
/// Cualquier otra dependencia ...
.package(url: "https://github.com/vapor/leaf.git", from: "4.0.0"),
.package(url: "https://github.com/vapor/leaf.git", from: "4.4.0"),
],
targets: [
.target(name: "App", dependencies: [
Expand Down
6 changes: 6 additions & 0 deletions docs/leaf/overview.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ Puede pasar una cadena de formateado de fecha personalizada como segundo argumen
The date is #date(now, "yyyy-MM-dd")
```

También puedes pasar un ID de zona horaria para el formateador de fechas como tercer argumento. Consulta la documentación de Swift sobre [`DateFormatter.timeZone`](https://developer.apple.com/documentation/foundation/dateformatter/1411406-timezone) y [`TimeZone`](https://developer.apple.com/documentation/foundation/timezone) para más información.

```leaf
The date is #date(now, "yyyy-MM-dd", "America/New_York")
```

#### `#unsafeHTML`

La etiqueta `#unsafeHTML` actúa como una etiqueta variable - p. ej. `#(variable)`. Sin embargo, no escapa ningún HTML que `variable` pueda contener:
Expand Down
Loading