@acvl/mobile-components 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/lib/module/camara/CampoDeFotos.js +4 -2
- package/lib/module/camara/CampoDeFotos.js.map +1 -1
- package/lib/module/camara/elegir.js +4 -3
- package/lib/module/camara/elegir.js.map +1 -1
- package/lib/module/componentes/AccionesDelEncabezado.js +3 -1
- package/lib/module/componentes/AccionesDelEncabezado.js.map +1 -1
- package/lib/module/componentes/BotonDeAvatar.js +24 -20
- package/lib/module/componentes/BotonDeAvatar.js.map +1 -1
- package/lib/module/componentes/CabeceraEmpujada.js +3 -1
- package/lib/module/componentes/CabeceraEmpujada.js.map +1 -1
- package/lib/module/componentes/PantallaDeError.js +6 -4
- package/lib/module/componentes/PantallaDeError.js.map +1 -1
- package/lib/module/componentes/TiraDeFotos.js +4 -2
- package/lib/module/componentes/TiraDeFotos.js.map +1 -1
- package/lib/module/componentes/VisorDeFoto.js +6 -4
- package/lib/module/componentes/VisorDeFoto.js.map +1 -1
- package/lib/module/dialogos/HostDeDialogos.js +3 -1
- package/lib/module/dialogos/HostDeDialogos.js.map +1 -1
- package/lib/module/dialogos/dialogos.js +6 -4
- package/lib/module/dialogos/dialogos.js.map +1 -1
- package/lib/module/formularios/SelectorDeOpcion.js +13 -7
- package/lib/module/formularios/SelectorDeOpcion.js.map +1 -1
- package/lib/module/formularios/campos.js +9 -4
- package/lib/module/formularios/campos.js.map +1 -1
- package/lib/module/formularios/guardado.js +4 -2
- package/lib/module/formularios/guardado.js.map +1 -1
- package/lib/module/fotos/elegir.js +10 -8
- package/lib/module/fotos/elegir.js.map +1 -1
- package/lib/module/hoja/HojaDeLista.js +5 -3
- package/lib/module/hoja/HojaDeLista.js.map +1 -1
- package/lib/module/hoja/useMasDeLaFicha.js +3 -1
- package/lib/module/hoja/useMasDeLaFicha.js.map +1 -1
- package/lib/module/idioma/ProveedorDeIdioma.js +54 -0
- package/lib/module/idioma/ProveedorDeIdioma.js.map +1 -0
- package/lib/module/idioma/index.js +4 -0
- package/lib/module/idioma/index.js.map +1 -0
- package/lib/module/idioma/textos.js +239 -0
- package/lib/module/idioma/textos.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/listas/HojaDeFiltros.js +11 -8
- package/lib/module/listas/HojaDeFiltros.js.map +1 -1
- package/lib/module/listas/ListaPaginada.js +6 -4
- package/lib/module/listas/ListaPaginada.js.map +1 -1
- package/lib/module/listas/piezas.js +13 -7
- package/lib/module/listas/piezas.js.map +1 -1
- package/lib/module/pantallas/PantallaDeAcceso.js +22 -7
- package/lib/module/pantallas/PantallaDeAcceso.js.map +1 -1
- package/lib/module/pantallas/PantallaDeEdicion.js +9 -6
- package/lib/module/pantallas/PantallaDeEdicion.js.map +1 -1
- package/lib/module/pantallas/PantallaDeFicha.js +7 -5
- package/lib/module/pantallas/PantallaDeFicha.js.map +1 -1
- package/lib/module/pantallas/PantallaDeHistorial.js +18 -14
- package/lib/module/pantallas/PantallaDeHistorial.js.map +1 -1
- package/lib/module/pantallas/PantallaDePerfil.js +12 -10
- package/lib/module/pantallas/PantallaDePerfil.js.map +1 -1
- package/lib/typescript/src/camara/CampoDeFotos.d.ts.map +1 -1
- package/lib/typescript/src/camara/elegir.d.ts.map +1 -1
- package/lib/typescript/src/componentes/AccionesDelEncabezado.d.ts.map +1 -1
- package/lib/typescript/src/componentes/BotonDeAvatar.d.ts.map +1 -1
- package/lib/typescript/src/componentes/CabeceraEmpujada.d.ts.map +1 -1
- package/lib/typescript/src/componentes/PantallaDeError.d.ts.map +1 -1
- package/lib/typescript/src/componentes/TiraDeFotos.d.ts.map +1 -1
- package/lib/typescript/src/componentes/VisorDeFoto.d.ts.map +1 -1
- package/lib/typescript/src/dialogos/HostDeDialogos.d.ts.map +1 -1
- package/lib/typescript/src/dialogos/dialogos.d.ts.map +1 -1
- package/lib/typescript/src/formularios/SelectorDeOpcion.d.ts.map +1 -1
- package/lib/typescript/src/formularios/campos.d.ts.map +1 -1
- package/lib/typescript/src/formularios/guardado.d.ts.map +1 -1
- package/lib/typescript/src/fotos/elegir.d.ts.map +1 -1
- package/lib/typescript/src/hoja/HojaDeLista.d.ts.map +1 -1
- package/lib/typescript/src/hoja/useMasDeLaFicha.d.ts.map +1 -1
- package/lib/typescript/src/idioma/ProveedorDeIdioma.d.ts +16 -0
- package/lib/typescript/src/idioma/ProveedorDeIdioma.d.ts.map +1 -0
- package/lib/typescript/src/idioma/index.d.ts +3 -0
- package/lib/typescript/src/idioma/index.d.ts.map +1 -0
- package/lib/typescript/src/idioma/textos.d.ts +125 -0
- package/lib/typescript/src/idioma/textos.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/listas/HojaDeFiltros.d.ts.map +1 -1
- package/lib/typescript/src/listas/ListaPaginada.d.ts.map +1 -1
- package/lib/typescript/src/listas/piezas.d.ts.map +1 -1
- package/lib/typescript/src/pantallas/PantallaDeAcceso.d.ts +5 -2
- package/lib/typescript/src/pantallas/PantallaDeAcceso.d.ts.map +1 -1
- package/lib/typescript/src/pantallas/PantallaDeEdicion.d.ts.map +1 -1
- package/lib/typescript/src/pantallas/PantallaDeFicha.d.ts.map +1 -1
- package/lib/typescript/src/pantallas/PantallaDeHistorial.d.ts.map +1 -1
- package/lib/typescript/src/pantallas/PantallaDePerfil.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/camara/CampoDeFotos.tsx +4 -2
- package/src/camara/elegir.ts +4 -3
- package/src/componentes/AccionesDelEncabezado.tsx +3 -1
- package/src/componentes/BotonDeAvatar.tsx +22 -18
- package/src/componentes/CabeceraEmpujada.tsx +3 -1
- package/src/componentes/PantallaDeError.tsx +6 -4
- package/src/componentes/TiraDeFotos.tsx +4 -2
- package/src/componentes/VisorDeFoto.tsx +7 -7
- package/src/dialogos/HostDeDialogos.tsx +3 -1
- package/src/dialogos/dialogos.ts +15 -4
- package/src/formularios/SelectorDeOpcion.tsx +22 -8
- package/src/formularios/campos.tsx +9 -4
- package/src/formularios/guardado.ts +4 -2
- package/src/fotos/elegir.ts +14 -10
- package/src/hoja/HojaDeLista.tsx +5 -5
- package/src/hoja/useMasDeLaFicha.tsx +3 -1
- package/src/idioma/ProveedorDeIdioma.tsx +51 -0
- package/src/idioma/index.ts +7 -0
- package/src/idioma/textos.ts +248 -0
- package/src/index.ts +11 -0
- package/src/listas/HojaDeFiltros.tsx +10 -9
- package/src/listas/ListaPaginada.tsx +6 -6
- package/src/listas/piezas.tsx +17 -10
- package/src/pantallas/PantallaDeAcceso.tsx +24 -5
- package/src/pantallas/PantallaDeEdicion.tsx +13 -6
- package/src/pantallas/PantallaDeFicha.tsx +7 -5
- package/src/pantallas/PantallaDeHistorial.tsx +22 -16
- package/src/pantallas/PantallaDePerfil.tsx +12 -10
package/src/hoja/HojaDeLista.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import { EnHoja } from "../componentes/Tarjeta";
|
|
|
13
13
|
import { Buscador } from "../listas/piezas";
|
|
14
14
|
import { crearEstilos, renglon, tipografia, usePaleta } from "../tema";
|
|
15
15
|
import { Text } from "../texto";
|
|
16
|
+
import { useTextos } from "../idioma";
|
|
16
17
|
|
|
17
18
|
/** Lo alto de la hoja: arriba se sigue viendo un poco de la ficha, que dice dónde se está. */
|
|
18
19
|
const ALTO = "85%";
|
|
@@ -76,6 +77,7 @@ export default function HojaDeLista<T>({
|
|
|
76
77
|
}) {
|
|
77
78
|
const c = usePaleta();
|
|
78
79
|
const styles = useStyles();
|
|
80
|
+
const t = useTextos();
|
|
79
81
|
const hoja = useRef<BottomSheet>(null);
|
|
80
82
|
const insets = useSafeAreaInsets();
|
|
81
83
|
|
|
@@ -123,9 +125,7 @@ export default function HojaDeLista<T>({
|
|
|
123
125
|
) : null}
|
|
124
126
|
{acciones}
|
|
125
127
|
{nombres && total != null && renglones.length ? (
|
|
126
|
-
<Text style={styles.cuenta}>
|
|
127
|
-
{total === 1 ? `1 ${nombres[0]}` : `${total} ${nombres[1]}`}
|
|
128
|
-
</Text>
|
|
128
|
+
<Text style={styles.cuenta}>{t.listas.cuantos(total, nombres)}</Text>
|
|
129
129
|
) : null}
|
|
130
130
|
</View>
|
|
131
131
|
);
|
|
@@ -134,9 +134,9 @@ export default function HojaDeLista<T>({
|
|
|
134
134
|
<ActivityIndicator color={c.primary} style={styles.espera} />
|
|
135
135
|
) : lista.fallo ? (
|
|
136
136
|
<View style={styles.vacio}>
|
|
137
|
-
<Text style={styles.linea}>
|
|
137
|
+
<Text style={styles.linea}>{t.ficha.hojaNoCargo}</Text>
|
|
138
138
|
<BotonGrande icono="refresh" modo="contorno" onPress={lista.onReintentar}>
|
|
139
|
-
|
|
139
|
+
{t.comun.reintentar}
|
|
140
140
|
</BotonGrande>
|
|
141
141
|
</View>
|
|
142
142
|
) : (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import HojaInferior from "./HojaInferior";
|
|
2
2
|
import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons";
|
|
3
3
|
import React from "react";
|
|
4
|
+
import { useTextos } from "../idioma";
|
|
4
5
|
import { FilaConContador, SeccionDeFicha } from "../listas/piezas";
|
|
5
6
|
|
|
6
7
|
/** Una lista de «Más»: su renglón con contador y lo que abre en la hoja. */
|
|
@@ -26,13 +27,14 @@ export interface ListaDeLaFicha {
|
|
|
26
27
|
*/
|
|
27
28
|
export function useMasDeLaFicha(listas: ListaDeLaFicha[], subtitulo?: string) {
|
|
28
29
|
// Lo que enseña se queda al cerrarla, para que su título no se vacíe mientras baja.
|
|
30
|
+
const t = useTextos();
|
|
29
31
|
const [clave, setClave] = React.useState<string | null>(null);
|
|
30
32
|
const [abierta, setAbierta] = React.useState(false);
|
|
31
33
|
const cerrar = React.useCallback(() => setAbierta(false), []);
|
|
32
34
|
const elegida = listas.find((l) => l.clave === clave);
|
|
33
35
|
|
|
34
36
|
const seccion = listas.length ? (
|
|
35
|
-
<SeccionDeFicha titulo=
|
|
37
|
+
<SeccionDeFicha titulo={t.ficha.mas}>
|
|
36
38
|
{listas.map((l) => (
|
|
37
39
|
<FilaConContador
|
|
38
40
|
key={l.clave}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { createContext, useContext } from "react";
|
|
2
|
+
import TEXTOS, { type Idioma, type Textos } from "./textos";
|
|
3
|
+
|
|
4
|
+
// ==============================|| IDIOMA ||============================== //
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* El idioma en el que la librería dibuja lo suyo. La librería **no traduce**: recibe el idioma ya
|
|
8
|
+
* resuelto y elige diccionario. De dónde sale (el teléfono, un claim del token, lo que el usuario
|
|
9
|
+
* eligió) y dónde se cambia es asunto de la app. Es el mismo trato que `LocaleProvider` en
|
|
10
|
+
* `@acvl/frontend-components`.
|
|
11
|
+
*
|
|
12
|
+
* Sin proveedor el idioma es español, que es como se comportaba antes de que esto existiera: una
|
|
13
|
+
* app que no lo monta no cambia en nada.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <ProveedorDeIdioma idioma={idioma}>
|
|
17
|
+
* <Stack />
|
|
18
|
+
* </ProveedorDeIdioma>
|
|
19
|
+
*/
|
|
20
|
+
const ContextoDeIdioma = createContext<Idioma>("es");
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* El idioma vigente para lo que corre fuera de un componente (`avisar`, `confirmar`,
|
|
24
|
+
* `elegirAdjunto`): no pueden leer un contexto. Lo pone el proveedor al pintarse.
|
|
25
|
+
*/
|
|
26
|
+
let idiomaVigente: Idioma = "es";
|
|
27
|
+
|
|
28
|
+
export function ProveedorDeIdioma({
|
|
29
|
+
idioma,
|
|
30
|
+
children,
|
|
31
|
+
}: {
|
|
32
|
+
idioma: Idioma;
|
|
33
|
+
children: React.ReactNode;
|
|
34
|
+
}) {
|
|
35
|
+
// En el render y no en un efecto: un `avisar` que salga del primer render de los hijos ya
|
|
36
|
+
// tiene que hablar el idioma nuevo. Es idempotente, así que StrictMode no lo descompone.
|
|
37
|
+
idiomaVigente = idioma;
|
|
38
|
+
return <ContextoDeIdioma.Provider value={idioma}>{children}</ContextoDeIdioma.Provider>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** El idioma activo de la librería. */
|
|
42
|
+
export const useIdiomaDeLaLibreria = (): Idioma => useContext(ContextoDeIdioma);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Los textos de la librería en el idioma activo. Devuelve el diccionario entero y no una función:
|
|
46
|
+
* `t.comun.cerrar` se autocompleta y una llave mal escrita no compila.
|
|
47
|
+
*/
|
|
48
|
+
export const useTextos = (): Textos => TEXTOS[useContext(ContextoDeIdioma)] ?? TEXTOS.es;
|
|
49
|
+
|
|
50
|
+
/** Los textos fuera de un componente; dentro de uno, `useTextos`. */
|
|
51
|
+
export const textosActuales = (): Textos => TEXTOS[idiomaVigente] ?? TEXTOS.es;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// ==============================|| TEXTOS DE LA LIBRERÍA ||============================== //
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Los textos que la librería dibuja por su cuenta, en los dos idiomas. Es el espejo del de
|
|
5
|
+
* `@acvl/frontend-components`: un diccionario tipado y no un runtime de i18n, para que cada app
|
|
6
|
+
* traiga el suyo (o ninguno) sin que la librería le imponga `i18next`. A `en` le falta una llave y
|
|
7
|
+
* no compila.
|
|
8
|
+
*
|
|
9
|
+
* El idioma lo pone la app con `ProveedorDeIdioma`; se lee con `useTextos()` en un componente y con
|
|
10
|
+
* `textosActuales()` fuera de uno (`avisar`, `elegirAdjunto`).
|
|
11
|
+
*
|
|
12
|
+
* Las plantillas van como funciones: el orden de las palabras cambia entre idiomas y una
|
|
13
|
+
* concatenación en el punto de uso lo fija.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Idiomas que entiende la librería. */
|
|
17
|
+
export type Idioma = "es" | "en";
|
|
18
|
+
|
|
19
|
+
const es = {
|
|
20
|
+
comun: {
|
|
21
|
+
cancelar: "Cancelar",
|
|
22
|
+
cerrar: "Cerrar",
|
|
23
|
+
entendido: "Entendido",
|
|
24
|
+
reintentar: "Reintentar",
|
|
25
|
+
listo: "Listo",
|
|
26
|
+
quitar: "Quitar",
|
|
27
|
+
elegir: "Elegir…",
|
|
28
|
+
buscar: "Buscar",
|
|
29
|
+
ninguno: "Ninguno",
|
|
30
|
+
noDisponible: "N/A",
|
|
31
|
+
si: "Sí",
|
|
32
|
+
no: "No",
|
|
33
|
+
atras: "Atrás",
|
|
34
|
+
revisaLaSenal: "Revisa tu señal e intenta de nuevo.",
|
|
35
|
+
noSePudoCargar: "No se pudo cargar",
|
|
36
|
+
},
|
|
37
|
+
acceso: {
|
|
38
|
+
usuario: "Usuario",
|
|
39
|
+
contrasena: "Contraseña",
|
|
40
|
+
entrar: "Iniciar Sesión",
|
|
41
|
+
noSePudo: "No se pudo iniciar sesión. Intente de nuevo.",
|
|
42
|
+
olvide: "¿Olvidaste tu contraseña?",
|
|
43
|
+
},
|
|
44
|
+
perfil: {
|
|
45
|
+
titulo: "Perfil",
|
|
46
|
+
apariencia: "Apariencia",
|
|
47
|
+
telefono: "Teléfono",
|
|
48
|
+
claro: "Claro",
|
|
49
|
+
oscuro: "Oscuro",
|
|
50
|
+
cerrarSesion: "Cerrar sesión",
|
|
51
|
+
},
|
|
52
|
+
error: {
|
|
53
|
+
titulo: "Algo salió mal",
|
|
54
|
+
mensaje:
|
|
55
|
+
"Esta pantalla no se pudo abrir. Intenta de nuevo; si vuelve a pasar, avisa a soporte.",
|
|
56
|
+
},
|
|
57
|
+
ficha: {
|
|
58
|
+
noExiste: "No existe",
|
|
59
|
+
noExisteTexto: "Puede que lo hayan borrado, o que no tengas permiso de verlo.",
|
|
60
|
+
mas: "Más",
|
|
61
|
+
hojaNoCargo: "No se pudo cargar. Revisa tu señal.",
|
|
62
|
+
seccionNoCargo: "No se pudo cargar. Jala la ficha para releer.",
|
|
63
|
+
},
|
|
64
|
+
edicion: {
|
|
65
|
+
sinPermiso: "No tienes permiso",
|
|
66
|
+
noSePudoCargar: (queEs: string) => `No se pudo cargar ${queEs}`,
|
|
67
|
+
guardar: "Guardar",
|
|
68
|
+
guardando: "Guardando…",
|
|
69
|
+
noSeGuardo: "No se guardó",
|
|
70
|
+
},
|
|
71
|
+
listas: {
|
|
72
|
+
cuantos: (total: number, [uno, varios]: readonly [string, string]) =>
|
|
73
|
+
total === 1 ? `1 ${uno}` : `${total} ${varios}`,
|
|
74
|
+
borrarBusqueda: "Borrar búsqueda",
|
|
75
|
+
filtrosPuestos: (cuenta: number) => `Filtros, ${cuenta} puestos`,
|
|
76
|
+
filtrosYOrden: "Filtros y orden",
|
|
77
|
+
filtros: "Filtros",
|
|
78
|
+
ver: (total: number, [uno, varios]: readonly [string, string]) =>
|
|
79
|
+
`Ver ${total} ${total === 1 ? uno : varios}`,
|
|
80
|
+
ordenarPor: "Ordenar por",
|
|
81
|
+
sentido: "Sentido",
|
|
82
|
+
ascendente: "Ascendente",
|
|
83
|
+
descendente: "Descendente",
|
|
84
|
+
nadaQueCoincida: "Nada que coincida.",
|
|
85
|
+
listoCon: (n: number) => `Listo (${n})`,
|
|
86
|
+
masAcciones: "Más acciones",
|
|
87
|
+
},
|
|
88
|
+
contacto: {
|
|
89
|
+
llamar: (nombre: string) => `Llamar a ${nombre}`,
|
|
90
|
+
whatsapp: (nombre: string) => `WhatsApp a ${nombre}`,
|
|
91
|
+
correo: (nombre: string) => `Correo a ${nombre}`,
|
|
92
|
+
direccion: "Dirección",
|
|
93
|
+
abrirEnElMapa: (donde: string) => `Abrir en el mapa: ${donde}`,
|
|
94
|
+
},
|
|
95
|
+
campos: {
|
|
96
|
+
diezDigitos: "10 dígitos",
|
|
97
|
+
},
|
|
98
|
+
fotos: {
|
|
99
|
+
verLaFoto: "Ver la foto",
|
|
100
|
+
archivo: (nombre: string) => `Archivo ${nombre}`.trim(),
|
|
101
|
+
quitarFoto: "Quitar esta foto",
|
|
102
|
+
quitarArchivo: "Quitar este archivo",
|
|
103
|
+
guardada: "Guardada en la galería",
|
|
104
|
+
noSeGuardo: "No se pudo guardar; intentar de nuevo",
|
|
105
|
+
guardarEnGaleria: "Guardar en la galería",
|
|
106
|
+
deTotal: (n: number, total: number) => `${n} de ${total}`,
|
|
107
|
+
tomarFoto: "Tomar foto",
|
|
108
|
+
tomarUnaFoto: "Tomar una foto",
|
|
109
|
+
deLaGaleria: "De la galería",
|
|
110
|
+
unDocumento: "Un documento",
|
|
111
|
+
subirArchivo: "Subir un archivo",
|
|
112
|
+
sinPermisoDeCamara: "Sin permiso de cámara",
|
|
113
|
+
activaLaCamara: (para: string) =>
|
|
114
|
+
`Para ${para}, activa la cámara para la app en los ajustes del teléfono.`,
|
|
115
|
+
laCamara: "La cámara",
|
|
116
|
+
demasiadoPesado: "Archivo demasiado pesado",
|
|
117
|
+
pesaDeMas: (nombre: string, pesaMb: string, topeMb: number) =>
|
|
118
|
+
`«${nombre}» pesa ${pesaMb} MB y el tope son ${topeMb} MB. Elige uno más ligero o tómale una foto.`,
|
|
119
|
+
},
|
|
120
|
+
historial: {
|
|
121
|
+
titulo: "Historial",
|
|
122
|
+
sistema: "Sistema",
|
|
123
|
+
sinCambios: "Sin cambios en los campos.",
|
|
124
|
+
ocultarCampos: "Ocultar campos",
|
|
125
|
+
verTodos: "Ver todos los campos",
|
|
126
|
+
verCampos: "Ver los campos",
|
|
127
|
+
noCargo: "No se pudo cargar el historial",
|
|
128
|
+
sinMovimientos: "Sin movimientos registrados",
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export type Textos = typeof es;
|
|
133
|
+
|
|
134
|
+
const en: Textos = {
|
|
135
|
+
comun: {
|
|
136
|
+
cancelar: "Cancel",
|
|
137
|
+
cerrar: "Close",
|
|
138
|
+
entendido: "Got it",
|
|
139
|
+
reintentar: "Try again",
|
|
140
|
+
listo: "Done",
|
|
141
|
+
quitar: "Clear",
|
|
142
|
+
elegir: "Choose…",
|
|
143
|
+
buscar: "Search",
|
|
144
|
+
ninguno: "None",
|
|
145
|
+
noDisponible: "N/A",
|
|
146
|
+
si: "Yes",
|
|
147
|
+
no: "No",
|
|
148
|
+
atras: "Back",
|
|
149
|
+
revisaLaSenal: "Check your connection and try again.",
|
|
150
|
+
noSePudoCargar: "Couldn't load",
|
|
151
|
+
},
|
|
152
|
+
acceso: {
|
|
153
|
+
usuario: "Username",
|
|
154
|
+
contrasena: "Password",
|
|
155
|
+
entrar: "Sign in",
|
|
156
|
+
noSePudo: "Couldn't sign in. Please try again.",
|
|
157
|
+
olvide: "Forgot your password?",
|
|
158
|
+
},
|
|
159
|
+
perfil: {
|
|
160
|
+
titulo: "Profile",
|
|
161
|
+
apariencia: "Appearance",
|
|
162
|
+
telefono: "Phone",
|
|
163
|
+
claro: "Light",
|
|
164
|
+
oscuro: "Dark",
|
|
165
|
+
cerrarSesion: "Sign out",
|
|
166
|
+
},
|
|
167
|
+
error: {
|
|
168
|
+
titulo: "Something went wrong",
|
|
169
|
+
mensaje: "This screen couldn't open. Try again; if it keeps happening, contact support.",
|
|
170
|
+
},
|
|
171
|
+
ficha: {
|
|
172
|
+
noExiste: "Not found",
|
|
173
|
+
noExisteTexto: "It may have been deleted, or you may not have permission to see it.",
|
|
174
|
+
mas: "More",
|
|
175
|
+
hojaNoCargo: "Couldn't load. Check your connection.",
|
|
176
|
+
seccionNoCargo: "Couldn't load. Pull down to refresh.",
|
|
177
|
+
},
|
|
178
|
+
edicion: {
|
|
179
|
+
sinPermiso: "You don't have permission",
|
|
180
|
+
noSePudoCargar: (queEs: string) => `Couldn't load ${queEs}`,
|
|
181
|
+
guardar: "Save",
|
|
182
|
+
guardando: "Saving…",
|
|
183
|
+
noSeGuardo: "Not saved",
|
|
184
|
+
},
|
|
185
|
+
listas: {
|
|
186
|
+
cuantos: (total: number, [uno, varios]: readonly [string, string]) =>
|
|
187
|
+
total === 1 ? `1 ${uno}` : `${total} ${varios}`,
|
|
188
|
+
borrarBusqueda: "Clear search",
|
|
189
|
+
filtrosPuestos: (cuenta: number) => `Filters, ${cuenta} applied`,
|
|
190
|
+
filtrosYOrden: "Filters and sorting",
|
|
191
|
+
filtros: "Filters",
|
|
192
|
+
ver: (total: number, [uno, varios]: readonly [string, string]) =>
|
|
193
|
+
`Show ${total} ${total === 1 ? uno : varios}`,
|
|
194
|
+
ordenarPor: "Sort by",
|
|
195
|
+
sentido: "Direction",
|
|
196
|
+
ascendente: "Ascending",
|
|
197
|
+
descendente: "Descending",
|
|
198
|
+
nadaQueCoincida: "No matches.",
|
|
199
|
+
listoCon: (n: number) => `Done (${n})`,
|
|
200
|
+
masAcciones: "More actions",
|
|
201
|
+
},
|
|
202
|
+
contacto: {
|
|
203
|
+
llamar: (nombre: string) => `Call ${nombre}`,
|
|
204
|
+
whatsapp: (nombre: string) => `WhatsApp ${nombre}`,
|
|
205
|
+
correo: (nombre: string) => `Email ${nombre}`,
|
|
206
|
+
direccion: "Address",
|
|
207
|
+
abrirEnElMapa: (donde: string) => `Open in maps: ${donde}`,
|
|
208
|
+
},
|
|
209
|
+
campos: {
|
|
210
|
+
diezDigitos: "10 digits",
|
|
211
|
+
},
|
|
212
|
+
fotos: {
|
|
213
|
+
verLaFoto: "View photo",
|
|
214
|
+
archivo: (nombre: string) => `File ${nombre}`.trim(),
|
|
215
|
+
quitarFoto: "Remove this photo",
|
|
216
|
+
quitarArchivo: "Remove this file",
|
|
217
|
+
guardada: "Saved to gallery",
|
|
218
|
+
noSeGuardo: "Couldn't save; try again",
|
|
219
|
+
guardarEnGaleria: "Save to gallery",
|
|
220
|
+
deTotal: (n: number, total: number) => `${n} of ${total}`,
|
|
221
|
+
tomarFoto: "Take photo",
|
|
222
|
+
tomarUnaFoto: "Take a photo",
|
|
223
|
+
deLaGaleria: "From gallery",
|
|
224
|
+
unDocumento: "A document",
|
|
225
|
+
subirArchivo: "Upload a file",
|
|
226
|
+
sinPermisoDeCamara: "No camera permission",
|
|
227
|
+
activaLaCamara: (para: string) =>
|
|
228
|
+
`To ${para}, turn on camera access for the app in your phone's settings.`,
|
|
229
|
+
laCamara: "The camera",
|
|
230
|
+
demasiadoPesado: "File too large",
|
|
231
|
+
pesaDeMas: (nombre: string, pesaMb: string, topeMb: number) =>
|
|
232
|
+
`"${nombre}" is ${pesaMb} MB and the limit is ${topeMb} MB. Choose a smaller one or take a photo of it.`,
|
|
233
|
+
},
|
|
234
|
+
historial: {
|
|
235
|
+
titulo: "History",
|
|
236
|
+
sistema: "System",
|
|
237
|
+
sinCambios: "No field changes.",
|
|
238
|
+
ocultarCampos: "Hide fields",
|
|
239
|
+
verTodos: "Show all fields",
|
|
240
|
+
verCampos: "Show fields",
|
|
241
|
+
noCargo: "Couldn't load the history",
|
|
242
|
+
sinMovimientos: "No recorded activity",
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const TEXTOS: Record<Idioma, Textos> = { es, en };
|
|
247
|
+
|
|
248
|
+
export default TEXTOS;
|
package/src/index.ts
CHANGED
|
@@ -151,3 +151,14 @@ export {
|
|
|
151
151
|
type Historial,
|
|
152
152
|
} from "./pantallas/PantallaDeHistorial";
|
|
153
153
|
export { default as PantallaDePerfil } from "./pantallas/PantallaDePerfil";
|
|
154
|
+
|
|
155
|
+
// ==============================|| IDIOMA ||============================== //
|
|
156
|
+
|
|
157
|
+
export {
|
|
158
|
+
ProveedorDeIdioma,
|
|
159
|
+
textosActuales,
|
|
160
|
+
useIdiomaDeLaLibreria,
|
|
161
|
+
useTextos,
|
|
162
|
+
type Idioma,
|
|
163
|
+
type Textos,
|
|
164
|
+
} from "./idioma";
|
|
@@ -6,6 +6,7 @@ import MaterialIcons from "@expo/vector-icons/MaterialIcons";
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { Modal, Pressable, ScrollView, Switch, TouchableOpacity, View } from "react-native";
|
|
8
8
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
9
|
+
import { useTextos } from "../idioma";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* La hoja de filtros y orden de una lista (viajes, recursos), a pantalla completa
|
|
@@ -35,17 +36,18 @@ export default function HojaDeFiltros({
|
|
|
35
36
|
const c = usePaleta();
|
|
36
37
|
const styles = useStyles();
|
|
37
38
|
const insets = useSafeAreaInsets();
|
|
39
|
+
const t = useTextos();
|
|
38
40
|
return (
|
|
39
41
|
<Modal visible={abierta} animationType="slide" onRequestClose={onCerrar}>
|
|
40
42
|
<View style={[styles.hoja, { paddingTop: insets.top + 10 }]}>
|
|
41
43
|
<View style={styles.cabecera}>
|
|
42
|
-
<TouchableOpacity onPress={onCerrar} accessibilityLabel=
|
|
44
|
+
<TouchableOpacity onPress={onCerrar} accessibilityLabel={t.comun.cerrar}>
|
|
43
45
|
<MaterialIcons name="arrow-back" size={45} color={c.primary} />
|
|
44
46
|
</TouchableOpacity>
|
|
45
|
-
<Text style={styles.titulo}>
|
|
47
|
+
<Text style={styles.titulo}>{t.listas.filtros}</Text>
|
|
46
48
|
{hayAlgo ? (
|
|
47
49
|
<TouchableOpacity onPress={onQuitar}>
|
|
48
|
-
<Text style={styles.limpiar}>
|
|
50
|
+
<Text style={styles.limpiar}>{t.comun.quitar}</Text>
|
|
49
51
|
</TouchableOpacity>
|
|
50
52
|
) : null}
|
|
51
53
|
</View>
|
|
@@ -54,9 +56,7 @@ export default function HojaDeFiltros({
|
|
|
54
56
|
|
|
55
57
|
<View style={{ paddingBottom: insets.bottom + 16 }}>
|
|
56
58
|
<BotonGrande onPress={onCerrar}>
|
|
57
|
-
{visibles === null
|
|
58
|
-
? "Listo"
|
|
59
|
-
: `Ver ${visibles} ${visibles === 1 ? nombres[0] : nombres[1]}`}
|
|
59
|
+
{visibles === null ? t.comun.listo : t.listas.ver(visibles, nombres)}
|
|
60
60
|
</BotonGrande>
|
|
61
61
|
</View>
|
|
62
62
|
</View>
|
|
@@ -205,17 +205,18 @@ export function OrdenDeLista({
|
|
|
205
205
|
onOrdenar: (orden: string | null) => void;
|
|
206
206
|
porOmision?: string;
|
|
207
207
|
}) {
|
|
208
|
+
const t = useTextos();
|
|
208
209
|
const descendente = orden?.startsWith("-") ?? false;
|
|
209
210
|
const campo = orden?.replace(/^-/, "");
|
|
210
211
|
const elegido = campos.find((c) => c.value === campo);
|
|
211
|
-
const sentidos = elegido?.sentidos ?? { asc:
|
|
212
|
+
const sentidos = elegido?.sentidos ?? { asc: t.listas.ascendente, desc: t.listas.descendente };
|
|
212
213
|
// El sentido con el que arranca va primero: en una fecha se lee «Recientes primero» antes
|
|
213
214
|
// que «Antiguos primero».
|
|
214
215
|
const ordenDeSentidos: ("asc" | "desc")[] =
|
|
215
216
|
elegido?.primero === "desc" ? ["desc", "asc"] : ["asc", "desc"];
|
|
216
217
|
return (
|
|
217
218
|
<>
|
|
218
|
-
<SeccionDeFiltros>
|
|
219
|
+
<SeccionDeFiltros>{t.listas.ordenarPor}</SeccionDeFiltros>
|
|
219
220
|
{porOmision ? (
|
|
220
221
|
<OpcionDeFiltro
|
|
221
222
|
texto={porOmision}
|
|
@@ -240,7 +241,7 @@ export function OrdenDeLista({
|
|
|
240
241
|
))}
|
|
241
242
|
{campo !== undefined ? (
|
|
242
243
|
<>
|
|
243
|
-
<SeccionDeFiltros>
|
|
244
|
+
<SeccionDeFiltros>{t.listas.sentido}</SeccionDeFiltros>
|
|
244
245
|
{ordenDeSentidos.map((sentido) => (
|
|
245
246
|
<OpcionDeFiltro
|
|
246
247
|
key={sentido}
|
|
@@ -7,6 +7,7 @@ import type MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIco
|
|
|
7
7
|
import React from "react";
|
|
8
8
|
import { ActivityIndicator, FlatList, RefreshControl } from "react-native";
|
|
9
9
|
import { renglonesDe, type Pagina } from "./paginado";
|
|
10
|
+
import { useTextos } from "../idioma";
|
|
10
11
|
|
|
11
12
|
/** Lo que la lista lee de un `use…InfiniteQuery` de RTK Query. */
|
|
12
13
|
export interface ConsultaPaginada<T> {
|
|
@@ -50,6 +51,7 @@ export default function ListaPaginada<T>({
|
|
|
50
51
|
}: Props<T>) {
|
|
51
52
|
const c = usePaleta();
|
|
52
53
|
const styles = useStyles();
|
|
54
|
+
const t = useTextos();
|
|
53
55
|
const renglones = renglonesDe(consulta.data);
|
|
54
56
|
const total = consulta.data?.pages[0]?.count;
|
|
55
57
|
|
|
@@ -60,11 +62,11 @@ export default function ListaPaginada<T>({
|
|
|
60
62
|
return (
|
|
61
63
|
<EstadoVacio
|
|
62
64
|
icono="cloud-off-outline"
|
|
63
|
-
titulo=
|
|
64
|
-
texto=
|
|
65
|
+
titulo={t.comun.noSePudoCargar}
|
|
66
|
+
texto={t.comun.revisaLaSenal}
|
|
65
67
|
>
|
|
66
68
|
<BotonGrande icono="refresh" onPress={() => consulta.refetch()}>
|
|
67
|
-
|
|
69
|
+
{t.comun.reintentar}
|
|
68
70
|
</BotonGrande>
|
|
69
71
|
</EstadoVacio>
|
|
70
72
|
);
|
|
@@ -78,9 +80,7 @@ export default function ListaPaginada<T>({
|
|
|
78
80
|
contentContainerStyle={[styles.contenido, !renglones.length && styles.vacia]}
|
|
79
81
|
ListHeaderComponent={
|
|
80
82
|
total !== undefined && renglones.length ? (
|
|
81
|
-
<Text style={styles.total}>
|
|
82
|
-
{total === 1 ? `1 ${nombres[0]}` : `${total} ${nombres[1]}`}
|
|
83
|
-
</Text>
|
|
83
|
+
<Text style={styles.total}>{t.listas.cuantos(total, nombres)}</Text>
|
|
84
84
|
) : null
|
|
85
85
|
}
|
|
86
86
|
ListEmptyComponent={
|
package/src/listas/piezas.tsx
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type TextInputProps,
|
|
21
21
|
type ViewStyle,
|
|
22
22
|
} from "react-native";
|
|
23
|
+
import { useTextos } from "../idioma";
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Las piezas de las listas y las fichas: la cabecera de una lista (buscador y pestañas), la
|
|
@@ -58,6 +59,7 @@ export function Buscador({
|
|
|
58
59
|
}) {
|
|
59
60
|
const c = usePaleta();
|
|
60
61
|
const styles = useStyles();
|
|
62
|
+
const t = useTextos();
|
|
61
63
|
const Campo = Entrada ?? TextInput;
|
|
62
64
|
return (
|
|
63
65
|
<View style={[styles.buscador, style]}>
|
|
@@ -90,7 +92,7 @@ export function Buscador({
|
|
|
90
92
|
<Pressable
|
|
91
93
|
onPress={() => onCambiar("")}
|
|
92
94
|
hitSlop={8}
|
|
93
|
-
accessibilityLabel=
|
|
95
|
+
accessibilityLabel={t.listas.borrarBusqueda}
|
|
94
96
|
>
|
|
95
97
|
<MaterialCommunityIcons name="close-circle" size={22} color={c.secondary} />
|
|
96
98
|
</Pressable>
|
|
@@ -114,13 +116,14 @@ export interface FiltrosDeCabecera {
|
|
|
114
116
|
*/
|
|
115
117
|
function BotonDeFiltros({ cuenta, punto, onPress }: FiltrosDeCabecera) {
|
|
116
118
|
const c = usePaleta();
|
|
119
|
+
const t = useTextos();
|
|
117
120
|
const styles = useStyles();
|
|
118
121
|
const activo = Boolean(cuenta) || punto;
|
|
119
122
|
return (
|
|
120
123
|
<Pressable
|
|
121
124
|
onPress={onPress}
|
|
122
125
|
accessibilityRole="button"
|
|
123
|
-
accessibilityLabel={cuenta ?
|
|
126
|
+
accessibilityLabel={cuenta ? t.listas.filtrosPuestos(cuenta) : t.listas.filtrosYOrden}
|
|
124
127
|
hitSlop={4}
|
|
125
128
|
style={({ pressed }) => [
|
|
126
129
|
styles.botonDeFiltros,
|
|
@@ -361,6 +364,7 @@ export function RenglonDeContacto({
|
|
|
361
364
|
}) {
|
|
362
365
|
const c = usePaleta();
|
|
363
366
|
const styles = useStyles();
|
|
367
|
+
const t = useTextos();
|
|
364
368
|
const boton = (
|
|
365
369
|
icono: React.ComponentProps<typeof MaterialCommunityIcons>["name"],
|
|
366
370
|
etiqueta: string,
|
|
@@ -386,15 +390,17 @@ export function RenglonDeContacto({
|
|
|
386
390
|
{correo ? <Text style={styles.linea}>{correo}</Text> : null}
|
|
387
391
|
</View>
|
|
388
392
|
<View style={styles.acciones}>
|
|
389
|
-
{telefono ? boton("phone",
|
|
393
|
+
{telefono ? boton("phone", t.contacto.llamar(nombre), `tel:${telefono}`) : null}
|
|
390
394
|
{telefono
|
|
391
395
|
? boton(
|
|
392
396
|
"whatsapp",
|
|
393
|
-
|
|
397
|
+
t.contacto.whatsapp(nombre),
|
|
394
398
|
`https://wa.me/${digitos(telefono)}`,
|
|
395
399
|
)
|
|
396
400
|
: null}
|
|
397
|
-
{correo
|
|
401
|
+
{correo
|
|
402
|
+
? boton("email-outline", t.contacto.correo(nombre), `mailto:${correo}`)
|
|
403
|
+
: null}
|
|
398
404
|
</View>
|
|
399
405
|
</View>
|
|
400
406
|
);
|
|
@@ -418,7 +424,7 @@ const abrirEnMapas = (direccion: string) => {
|
|
|
418
424
|
* no hay renglón. Es el hermano de `RenglonDeContacto`.
|
|
419
425
|
*/
|
|
420
426
|
export function RenglonDeDireccion({
|
|
421
|
-
etiqueta
|
|
427
|
+
etiqueta,
|
|
422
428
|
lineas,
|
|
423
429
|
enHoja,
|
|
424
430
|
}: {
|
|
@@ -430,13 +436,14 @@ export function RenglonDeDireccion({
|
|
|
430
436
|
}) {
|
|
431
437
|
const c = usePaleta();
|
|
432
438
|
const styles = useStyles();
|
|
439
|
+
const t = useTextos();
|
|
433
440
|
const presentes = lineas.map((l) => l?.trim()).filter((l): l is string => Boolean(l));
|
|
434
441
|
if (!presentes.length) return null;
|
|
435
442
|
return (
|
|
436
443
|
<Pressable
|
|
437
444
|
onPress={() => abrirEnMapas(presentes.join(", "))}
|
|
438
445
|
accessibilityRole="link"
|
|
439
|
-
accessibilityLabel={
|
|
446
|
+
accessibilityLabel={t.contacto.abrirEnElMapa(presentes.join(", "))}
|
|
440
447
|
style={({ pressed }) => [
|
|
441
448
|
styles.renglon,
|
|
442
449
|
enHoja && styles.renglonEnHoja,
|
|
@@ -444,7 +451,7 @@ export function RenglonDeDireccion({
|
|
|
444
451
|
]}
|
|
445
452
|
>
|
|
446
453
|
<View style={styles.renglonTexto}>
|
|
447
|
-
<Text style={styles.etiqueta}>{etiqueta}</Text>
|
|
454
|
+
<Text style={styles.etiqueta}>{etiqueta ?? t.contacto.direccion}</Text>
|
|
448
455
|
{presentes.map((l, i) => (
|
|
449
456
|
<Text key={i} style={i === 0 ? styles.valor : styles.linea}>
|
|
450
457
|
{l}
|
|
@@ -544,9 +551,9 @@ export function EstadoDeHoja({
|
|
|
544
551
|
}) {
|
|
545
552
|
const c = usePaleta();
|
|
546
553
|
const styles = useStyles();
|
|
554
|
+
const t = useTextos();
|
|
547
555
|
if (cargando) return <ActivityIndicator color={c.primary} />;
|
|
548
|
-
if (fallo)
|
|
549
|
-
return <Text style={styles.linea}>No se pudo cargar. Jala la ficha para releer.</Text>;
|
|
556
|
+
if (fallo) return <Text style={styles.linea}>{t.ficha.seccionNoCargo}</Text>;
|
|
550
557
|
return vacio ? <Text style={styles.linea}>{vacio}</Text> : null;
|
|
551
558
|
}
|
|
552
559
|
|