From ecb73e1684b42265af3f8d93541600e4d0f9c414 Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Tue, 24 Jun 2025 16:14:28 +0200 Subject: Implement i18n Closes #18 --- src/frontend/app/routes/estimates-$id.tsx | 2 + src/frontend/app/routes/map.tsx | 2 + src/frontend/app/routes/settings.tsx | 69 ++++++++++++++++++------------- src/frontend/app/routes/stoplist.tsx | 16 ++----- 4 files changed, 47 insertions(+), 42 deletions(-) (limited to 'src/frontend/app/routes') diff --git a/src/frontend/app/routes/estimates-$id.tsx b/src/frontend/app/routes/estimates-$id.tsx index 761a8d4..5dbbc7d 100644 --- a/src/frontend/app/routes/estimates-$id.tsx +++ b/src/frontend/app/routes/estimates-$id.tsx @@ -6,6 +6,7 @@ import "./estimates-$id.css"; import { RegularTable } from "../components/RegularTable"; import { useApp } from "../AppContext"; import { GroupedTable } from "../components/GroupedTable"; +import { useTranslation } from "react-i18next"; export interface StopDetails { stop: { @@ -32,6 +33,7 @@ const loadData = async (stopId: string) => { }; export default function Estimates() { + const { t } = useTranslation(); const params = useParams(); const stopIdNum = parseInt(params.id ?? ""); const [customName, setCustomName] = useState(undefined); diff --git a/src/frontend/app/routes/map.tsx b/src/frontend/app/routes/map.tsx index a938148..ca095e2 100644 --- a/src/frontend/app/routes/map.tsx +++ b/src/frontend/app/routes/map.tsx @@ -8,6 +8,7 @@ import { loadStyle } from "app/maps/styleloader"; import type { Feature as GeoJsonFeature, Point } from 'geojson'; import LineIcon from "~/components/LineIcon"; import { Link } from "react-router"; +import { useTranslation } from "react-i18next"; // Default minimal fallback style before dynamic loading const defaultStyle: StyleSpecification = { @@ -20,6 +21,7 @@ const defaultStyle: StyleSpecification = { // Componente principal del mapa export default function StopMap() { + const { t } = useTranslation(); const [stops, setStops] = useState[]>([]); const [popupInfo, setPopupInfo] = useState(null); const { mapState, updateMapState, theme } = useApp(); diff --git a/src/frontend/app/routes/settings.tsx b/src/frontend/app/routes/settings.tsx index b5e91f1..e657c03 100644 --- a/src/frontend/app/routes/settings.tsx +++ b/src/frontend/app/routes/settings.tsx @@ -1,64 +1,75 @@ import { useApp } from "../AppContext"; import "./settings.css"; +import { useTranslation } from "react-i18next"; export default function Settings() { + const { t, i18n } = useTranslation(); const { theme, setTheme, tableStyle, setTableStyle, mapPositionMode, setMapPositionMode } = useApp(); return (
-

Sobre UrbanoVigo Web

+

{t('about.title')}

- Aplicación web para encontrar paradas y tiempos de llegada de los autobuses - urbanos de Vigo, España. + {t('about.description')}

-

Ajustes

+

{t('about.settings')}

- - setTheme(e.target.value as "light" | "dark")}> + +
- - setTableStyle(e.target.value as "regular" | "grouped")}> + +
- - setMapPositionMode(e.target.value as 'gps' | 'last')}> + + + +
+
+ +
- ¿Qué significa esto? -

- La tabla de horarios puede mostrarse de dos formas: -

+ {t('about.details_summary')} +

{t('about.details_table')}

-
Mostrar por orden
-
Las paradas se muestran en el orden en que se visitan. Aplicaciones como Infobus (Vitrasa) usan este estilo.
-
Agrupar por línea
-
Las paradas se agrupan por la línea de autobús. Aplicaciones como iTranvias (A Coruña) o Moovit (más o menos) usan este estilo.
+
{t('about.table_style_regular')}
+
{t('about.details_regular')}
+
{t('about.table_style_grouped')}
+
{t('about.details_grouped')}
-

Créditos

+

{t('about.credits')}

- Código en GitHub + {t('about.github')} - - Desarrollado por + {t('about.developed_by')} Ariel Costas

- Datos obtenidos de datos.vigo.org bajo - licencia Open Data Commons Attribution License + {t('about.data_source_prefix')} datos.vigo.org {t('about.data_source_middle')} Open Data Commons Attribution License

) diff --git a/src/frontend/app/routes/stoplist.tsx b/src/frontend/app/routes/stoplist.tsx index ff1da71..0ab6d15 100644 --- a/src/frontend/app/routes/stoplist.tsx +++ b/src/frontend/app/routes/stoplist.tsx @@ -3,25 +3,15 @@ import StopDataProvider, { type Stop } from "../data/StopDataProvider"; import StopItem from "../components/StopItem"; import Fuse from "fuse.js"; import './stoplist.css'; - -const placeholders = [ - "Urzaiz", - "Gran Vía", - "Castelao", - "García Barbón", - "Valladares", - "Florida", - "Pizarro", - "Estrada Madrid", - "Sanjurjo Badía" -]; +import { useTranslation } from "react-i18next"; export default function StopList() { + const { t } = useTranslation(); const [data, setData] = useState(null) const [searchResults, setSearchResults] = useState(null); const searchTimeout = useRef(null); - const randomPlaceholder = useMemo(() => placeholders[Math.floor(Math.random() * placeholders.length)], []); + const randomPlaceholder = useMemo(() => t('stoplist.search_placeholder'), [t]); const fuse = useMemo(() => new Fuse(data || [], { threshold: 0.3, keys: ['name.original'] }), [data]); useEffect(() => { -- cgit v1.3