Skip to content

Commit dbc6c4b

Browse files
committed
feat(tutorial): batch updates
- Multilanguage appendix - Angular +19 updates - Tutorial admonitions - Dates appendix
1 parent fcb5716 commit dbc6c4b

5 files changed

Lines changed: 164 additions & 1 deletion

File tree

docs/appendix/dates.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Fechas
2+
3+
Uno de los elementos más problemáticos en las aplicaciones son las fechas. Más concretamente, cómo las gestionamos.
4+
5+
Pero podemos afrontarlo de una manera más clara. Vamos a empezar con unas definiciones básicas, veremos por qué hay problemas y la solución que proponemos para que no te supongan un problema en tus aplicaciones.
6+
7+
## Definiciones básicas
8+
9+
Antes de nada, vamos a definir unos conceptos básicos que nos ayudarán a entender mejor el problema.
10+
11+
- **Fecha (Date)**: Una fecha es una representación de un día concreto en el calendario. Por ejemplo, "15 de junio de 2024".
12+
- **Hora (Time)**: La hora representa un momento específico dentro de un día. - **Zona horaria (Timezone)**: La zona horaria es una región geográfica que tiene la misma hora estándar. Por ejemplo, "CET" (Central European Time) o "GMT" (Greenwich Mean Time).
13+
- **Fecha y hora (DateTime)**: La combinación de fecha y hora representa un momento específico en el tiempo, incluyendo la zona horaria. Por ejemplo, "15 de junio de 2024 a las 14:30 CET".
14+
- **Timestamp**: Un timestamp es una representación numérica de un momento específico en el tiempo, generalmente expresado en segundos o milisegundos desde una fecha de referencia (por ejemplo, el 1 de enero de 1970, conocido como la "época Unix").
15+
16+
## Problemas comunes
17+
18+
Al trabajar con fechas y horas, pueden surgir varios problemas comunes:
19+
20+
- **Conversión de zonas horarias**: Si una aplicación maneja usuarios en diferentes zonas horarias, es crucial convertir correctamente las fechas y horas para evitar confusiones.
21+
- **Formato inconsistente**: Diferentes regiones utilizan diferentes formatos de fecha y hora, lo que puede llevar a errores de interpretación. Ej. DD/MM/AAAA (Europa) vs MM/DD/AAAA (EE.UU.).
22+
- **Diferencias en el horario de verano**: Las fechas y horas pueden verse afectadas por el horario de verano, lo que puede causar confusiones si no se maneja correctamente.
23+
- **Errores de cálculo**: Al realizar cálculos con fechas y horas (por ejemplo, sumar días o restar horas), es fácil cometer errores si no se consideran todos los factores relevantes.
24+
- **Me quita un día**: Es la más común al principio, ¿por qué ocurre esto? La respuesta está en cómo se manejan las zonas horarias y el horario de verano. Cuando le pasamos una fecha, estamos indicándole un día sin zona horaria, por lo que se detecta nuestra zona horaria local y se aplica el desfase correspondiente. GMT+1 en horario estándar y GMT+2 en horario de verano.
25+
26+
Lo importante es recordar que un día en una zona horaria puede no ser el mismo día en otra zona horaria. Por ejemplo, el 15 de junio de 2024 en CET puede ser el 14 de junio de 2024 en GMT, que es por lo que ocurre un descuento de día.
27+
28+
## Solución propuesta
29+
30+
Para evitar estos problemas, os proponemos adheriros al estándar ISO 8601 para representar fechas y horas en vuestras aplicaciones. Este estándar define un formato claro y consistente para las fechas y horas, que incluye la zona horaria.
31+
32+
El formato ISO 8601 para una fecha y hora completa con zona horaria es el siguiente:
33+
34+
```
35+
AAAA-MM-DDTHH:MM:SS.mmmZ±HH:MM
36+
```
37+
38+
Por ejemplo, "2024-06-15T14:30:00.000Z+02:00" representa el 15 de junio de 2024 a las 14:30 en la zona horaria GMT+2.
39+
40+
### Backend
41+
42+
En Java, para manejar fechas con ISO 8601 de forma segura, recomendamos el uso de `Date`, así, siempre que le pasen una fecha en formato ISO 8601, se gestionará correctamente la zona horaria.
43+
44+
```java
45+
import java.util.Date;
46+
47+
// ...
48+
49+
private Date fecha;
50+
```
51+
52+
### Frontend
53+
54+
El uso de fechas lo gestionaremos con ISO Date
55+
56+
```javascript
57+
// Para leer fechas en formato ISO 8601
58+
const fecha = new Date(`2024-06-15T14:30:00.000Z`);
59+
60+
// Para enviar fechas en formato ISO 8601
61+
const fechaISO = fecha.toISOString();
62+
```
63+
64+
## Buenas prácticas
65+
66+
- Siempre utiliza el formato ISO 8601 para representar fechas y horas en tus aplicaciones.
67+
- Asegúrate de manejar correctamente las zonas horarias al mostrar fechas y horas a los usuarios.
68+
- Realiza pruebas exhaustivas para verificar que las fechas y horas se manejan correctamente en diferentes escenarios y zonas horarias.
69+
- Nunca elimines las horas ni la zona horaria al manejar fechas. Siempre trabaja con fechas completas en formato ISO 8601.
70+
71+
Si te cuestionan por qué pasan un día y el servidor entiende otro, explícales que es por la zona horaria y que la solución es usar siempre ISO 8601. De esta manera la consistencia en los datos estará garantizada.

docs/appendix/multilanguage.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Multidioma
2+
3+
En las aplicaciones reales, un detalle de suma importancia es la capacidad de soportar múltiples idiomas para llegar a una audiencia más amplia. Afortunadamente, tanto en el frontend como en el backend, existen herramientas y bibliotecas que facilitan la implementación de esta funcionalidad.
4+
5+
En especial nos centraremos en el frontend.
6+
7+
## Backend
8+
9+
La comunicación del backend ha de ser agnóstica al idioma del cliente (frontend). Para conseguir este resultado, nos comunicaremos con códigos de error (o éxito). Estableceremos un estándar de códigos que el frontend interpretará y mostrará el mensaje adecuado en función del idioma seleccionado por el usuario.
10+
11+
Para cualquier información extra, por ejemplo, indicar el número máximo de juegos que pueden prestarse. Acordaremos un campo asociado al código de error que contendrá dicha información adicional.
12+
13+
## Frontend
14+
15+
Para el frontend, existen varias bibliotecas que facilitan la implementación de la funcionalidad multilingüe. Usaremos el estándar `i18n` de Angular, que permite definir archivos de traducción para cada idioma soportado. (Guía oficial de Internalización)[https://angular.dev/guide/i18n]
16+
17+
Los términos que has de tener en cuenta en esta nueva etapa son:
18+
19+
- `i18n`: Abreviatura de "internationalization" (internacionalización), donde 18 representa el número de letras entre la 'i' y la 'n'.
20+
- `locale`: Configuración regional que define el idioma y las convenciones culturales (formato de fecha, moneda, etc.) para una región específica. Ej. `es-ES` para español de España, `en-US` para inglés de Estados Unidos.
21+
22+
### Material
23+
24+
Angular Material también soporta la internacionalización. Para ello, es necesario importar los módulos de localización correspondientes y configurar el proveedor de localización en el módulo principal de la aplicación.
25+
26+
```typescript
27+
import { MAT_DATE_LOCALE } from "@angular/material/core";
28+
@NgModule({
29+
providers: [
30+
{ provide: MAT_DATE_LOCALE, useValue: "es-ES" }, // Cambia 'es-ES' por el locale deseado
31+
],
32+
})
33+
export class AppModule {}
34+
```
35+
36+
Esto evitará que tengamos un `Items per page: 10` en inglés en las tablas de paginación de Angular Material.
37+
38+
### Estructura de un fichero de traducciones
39+
40+
Crearemos ficheros de traducciones que contendrán `keys` (los códigos de acceso) y sus correspondientes valores en cada idioma. Por ejemplo, podríamos tener un fichero `en.json` para inglés y otro `es.json` para español.
41+
42+
- translations
43+
- en.json
44+
- es.json
45+
46+
Aunque solemos preferir nombres más explícitos:
47+
48+
- translations
49+
- en-US.json
50+
- es-ES.json
51+
52+
Un fichero de traducciones en Angular suele tener la siguiente estructura:
53+
54+
```json
55+
{
56+
"VIEWS": {
57+
"HOME": {
58+
"TITLE": "Título de la aplicación",
59+
"WELCOME_MESSAGE": "Bienvenido a nuestra aplicación",
60+
"LOGIN": "Iniciar sesión",
61+
"LOGOUT": "Cerrar sesión"
62+
},
63+
"DASHBOARD": {
64+
"TITLE": "Panel de control",
65+
"STATISTICS": "Estadísticas",
66+
"SETTINGS": "Configuraciones"
67+
}
68+
}
69+
}
70+
```
71+
72+
Ahora ya tienes todo lo necesario para crear aplicaciones multidioma. ¡Manos a la obra!

docs/develop/basic/angular17.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,14 @@ Una vez añadida la dependencia, lo que queremos es crear una primera estructura
5555

5656
Para agrupar los componentes comunes de nuestra aplicación vamos a crear una carpeta llamada "core" dentro de la carpeta "src", e iremos creando los componentes que necesitemos. Empecemos con el header. Desde la raíz de nuestro proyecto introducimos el siguiente comando:
5757

58+
5859
```
5960
ng generate component core/header
6061
```
6162

63+
!!! info "Angular 19+"
64+
A partir de Angular 19, los elementos se generan sin topología, es decir `*.component.html` -> `*.html`, `*.service.ts` -> `*.ts`, etc.
65+
6266
### Código de la pantalla
6367

6468
Esto nos creará una carpeta con los ficheros del componente, donde tendremos que copiar el siguiente contenido:
@@ -154,7 +158,10 @@ Esto nos creará una carpeta con los ficheros del componente, donde tendremos qu
154158
}
155159
```
156160

157-
Al utilizar etiquetas de material como `mat-toolbar` o `mat-icon` y `routerLink` necesitaremos importar las dependencias. Al tratarse de un standalone component lo tendremos que hacer directamente en el atributo "imports" de nuestro component en el fichero `header.component.ts`
161+
Al utilizar etiquetas de material como `mat-toolbar` o `mat-icon` y `routerLink` necesitaremos importar las dependencias. Al tratarse de un standalone component lo tendremos que hacer directamente en el atributo "imports" de nuestro component en el fichero `header.component.ts`.
162+
163+
!!! info "Angular 19+"
164+
A partir de Angular 19, los componentes se crean por defecto como `standalone`, para que este no sea el caso debemos indicárselo con `--standalone false`.
158165

159166
=== "header.component.ts"
160167
``` Typescript hl_lines="3 4 5 12 13 14"
@@ -591,6 +598,9 @@ Si refrescamos el navegador y pulsamos el botón `Nueva categoría`, veremos com
591598

592599
Ahora vamos a darle forma al formulario de editar y crear. Para ello vamos al html, ts y css del componente y pegamos el siguiente contenido:
593600

601+
!!!tip "Errores de validación"
602+
Os recomendamos seguir el siguiente formato para los errores de validación en formularios (`ngModel`, `mat-error`)
603+
594604
=== "category-edit.component.html"
595605
``` HTML
596606
<div class="container">

docs/exercise.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Ahora vamos a ver si has comprendido bien el tutorial. Voy a poner dos ejercicio
44

55
Nuestro amigo *Ernesto Esvida* ya tiene disponible su web para gestionar su catálogo de juegos, autores y categorías, pero todavía le falta un poco más para poder hacer buen uso de su ludoteca. Así que nos ha pedido dos funcionalidades extra.
66

7+
!!!tip "Ten en cuenta"
8+
Solo te pedimos que realices las funcionalidades que se indican en los requisitos. No es necesario que completes los anexos antes de que revisemos los resultados.
9+
710
## Gestión de clientes
811

912
### Requisitos
@@ -40,6 +43,9 @@ Nos ha pasado el siguiente boceto y requisitos:
4043

4144
![exercise_3](./assets/images/exercise_3.png)
4245

46+
!!!warning "Atención"
47+
Aunque no aparezca en el boceto, como en todas las listas que hemos visto, esperamos que puedan **editarse** los registros. El botón de "Filtrar" tendrá el mismo aspecto visual que el botón de "Nuevo préstamo".
48+
4349
La pantalla tendrá dos zonas:
4450

4551
- Una zona de filtrado donde se permitirá filtrar por:
@@ -83,6 +89,8 @@ Para empezar te daré unos consejos:
8389
- Si hiciste el backend en Springboot recuerda revisar [Baeldung](https://www.baeldung.com/spring-data-jpa-query) por si tienes dudas sobre las queries y recuerda que las `Specifications` son muy útiles, pero en este caso deberás implementar otro tipo de operaciones, no te sirve solo con la operación de igualdad `:`, que ya vimos en el tutorial.
8490
- Implementa la pantalla de alta de préstamo, sin ninguna validación.
8591
- Cuando ya te funcione, intenta ir añadiendo una a una las validaciones. Algunas de ellas pueden hacerse en frontend, mientras que otras deberán validarse en backend
92+
- Os recordamos que han de poder crearse y editarse préstamos según las reglas de validación indicadas anteriormente. Aplican las mismas reglas para ambas operaciones.
93+
- El Backend ha de validar siempre, independientemente de que el Frontend ya lo haya validado. Nunca confíes de manera exclusiva en terceras partes (Frontend o en otro Backend).
8694

8795

8896

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ nav:
6363
- Practiquemos: appendix/docker/traindocker.md
6464
- Resumen: appendix/docker/summary.md
6565
- AWS CLI: appendix/aws.md
66+
- Multidioma: appendix/multilanguage.md
67+
- Fechas: appendix/dates.md
6668
theme:
6769
name: material
6870
language: es

0 commit comments

Comments
 (0)