Skip to content

Commit

Permalink
Internationalize server
Browse files Browse the repository at this point in the history
  • Loading branch information
cdauth committed Apr 3, 2024
1 parent f4c6a2f commit dfc8570
Show file tree
Hide file tree
Showing 35 changed files with 281 additions and 139 deletions.
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
},
"dependencies": {
"facilmap-types": "workspace:^",
"serialize-error": "^11.0.3",
"socket.io-client": "^4.7.4"
},
"devDependencies": {
Expand Down
9 changes: 6 additions & 3 deletions client/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { io, type ManagerOptions, type Socket as SocketIO, type SocketOptions } from "socket.io-client";
import type { Bbox, BboxWithZoom, CRU, EventHandler, EventName, FindOnMapQuery, FindPadsQuery, FindPadsResult, FindQuery, GetPadQuery, HistoryEntry, ID, Line, LineExportRequest, LineTemplateRequest, LineToRouteCreate, SocketEvents, Marker, MultipleEvents, ObjectWithId, PadData, PadId, PagedResults, SocketRequest, SocketRequestName, SocketResponse, Route, RouteClear, RouteCreate, RouteExportRequest, RouteInfo, RouteRequest, SearchResult, SocketVersion, TrackPoint, Type, View, Writable, SocketClientToServerEvents, SocketServerToClientEvents, LineTemplate, LinePointsEvent } from "facilmap-types";
import { type Bbox, type BboxWithZoom, type CRU, type EventHandler, type EventName, type FindOnMapQuery, type FindPadsQuery, type FindPadsResult, type FindQuery, type GetPadQuery, type HistoryEntry, type ID, type Line, type LineExportRequest, type LineTemplateRequest, type LineToRouteCreate, type SocketEvents, type Marker, type MultipleEvents, type ObjectWithId, type PadData, type PadId, type PagedResults, type SocketRequest, type SocketRequestName, type SocketResponse, type Route, type RouteClear, type RouteCreate, type RouteExportRequest, type RouteInfo, type RouteRequest, type SearchResult, type SocketVersion, type TrackPoint, type Type, type View, type Writable, type SocketClientToServerEvents, type SocketServerToClientEvents, type LineTemplate, type LinePointsEvent, PadNotFoundError } from "facilmap-types";
import { deserializeError, errorConstructors } from "serialize-error";

export interface ClientEvents extends SocketEvents<SocketVersion.V2> {
connect: [];
Expand Down Expand Up @@ -65,6 +66,8 @@ interface ClientData {
routes: Record<string, RouteWithTrackPoints>;
}

errorConstructors.set("PadNotFoundError", PadNotFoundError as any);

export default class Client {
private socket: SocketIO<SocketServerToClientEvents<SocketVersion.V2>, SocketClientToServerEvents<SocketVersion.V2>>;
private state: ClientState;
Expand Down Expand Up @@ -192,9 +195,9 @@ export default class Client {
this._simulateEvent("emit", eventName as any, data as any);

return await new Promise((resolve, reject) => {
this.socket.emit(eventName as any, data, (err: Error, data: SocketResponse<SocketVersion.V2, R>) => {
this.socket.emit(eventName as any, data, (err: any, data: SocketResponse<SocketVersion.V2, R>) => {
if(err) {
reject(err);
reject(deserializeError(err));
this._simulateEvent("emitReject", eventName as any, err);
} else {
const fixedData = this._fixResponseObject(eventName, data);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const messagesDe = {
"map-data-pois": `POIs`,
"map-data-directions": `Routenberechnung`,
"map-data-geoip": `GeoIP`,
"map-data-geoip-description": `Dieses Produkt enthält GeoLine2-Daten von Maxmind, verfügbar unter {{maxmind}}.`,
"map-data-geoip-description": `Dieses Produkt enthält GeoLite2-Daten von Maxmind, verfügbar unter {{maxmind}}.`,
"attribution-osm-contributors": `OSM-Mitwirkende`,
"programs-libraries": `Programme/Bibliotheken`,
"icons": `Symbole`
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/client-provider.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { onBeforeUnmount, reactive, ref, toRaw, watch } from "vue";
import Client from "facilmap-client";
import type { PadData, PadId } from "facilmap-types";
import { PadNotFoundError, type PadData, type PadId } from "facilmap-types";
import PadSettingsDialog from "./pad-settings-dialog/pad-settings-dialog.vue";
import storage from "../utils/storage";
import { useToasts } from "./ui/toasts/toasts.vue";
Expand All @@ -10,7 +10,7 @@
import { injectContextRequired } from "./facil-map-context-provider/facil-map-context-provider.vue";
function isPadNotFoundError(serverError: Client["serverError"]): boolean {
return !!serverError?.message?.includes("does not exist");
return !!serverError && serverError instanceof PadNotFoundError;
}
</script>

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/line-info/line-info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { getZoomDestinationForLine } from "../../utils/zoom";
import RouteForm from "../route-form/route-form.vue";
import vTooltip from "../../utils/tooltip";
import { formatField, formatRouteTime, normalizeLineName, round } from "facilmap-utils";
import { formatDistance, formatField, formatRouteTime, normalizeLineName } from "facilmap-utils";
import { computed, ref } from "vue";
import { useToasts } from "../ui/toasts/toasts.vue";
import { showConfirm } from "../ui/alert.vue";
Expand Down Expand Up @@ -160,7 +160,7 @@
<div class="fm-search-box-collapse-point" v-if="!isMoving">
<dl class="fm-search-box-dl">
<dt class="distance">Distance</dt>
<dd class="distance">{{round(line.distance, 2)}}&#x202F;km <span v-if="line.time != null">({{formatRouteTime(line.time, line.mode)}})</span></dd>
<dd class="distance">{{formatDistance(line.distance)}} <span v-if="line.time != null">({{formatRouteTime(line.time, line.mode)}})</span></dd>

<template v-if="line.ascent != null">
<dt class="elevation">Climb/drop</dt>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/lib/components/route-form/route-form.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed, markRaw, onBeforeUnmount, onMounted, ref, watch, watchEffect } from "vue";
import Icon from "../ui/icon.vue";
import { formatRouteTime, isSearchId, normalizeMarkerName, round, splitRouteQuery } from "facilmap-utils";
import { formatCoordinates, formatDistance, formatRouteTime, isSearchId, normalizeMarkerName, splitRouteQuery } from "facilmap-utils";
import { useToasts } from "../ui/toasts/toasts.vue";
import type { ExportFormat, FindOnMapResult, SearchResult } from "facilmap-types";
import { getMarkerIcon, type HashQuery, MarkerLayer, RouteLayer } from "facilmap-leaflet";
Expand Down Expand Up @@ -38,7 +38,7 @@
}
function makeCoordDestination(latlng: LatLng) {
const disp = round(latlng.lat, 5) + "," + round(latlng.lng, 5);
const disp = formatCoordinates({ lat: latlng.lat, lon: latlng.lng });
let suggestion = {
lat: latlng.lat,
lon: latlng.lng,
Expand Down Expand Up @@ -670,7 +670,7 @@

<dl class="fm-search-box-dl">
<dt>Distance</dt>
<dd>{{round(routeObj.distance, 2)}}&#x202F;km <span v-if="routeObj.time != null">({{formatRouteTime(routeObj.time, routeObj.mode)}})</span></dd>
<dd>{{formatDistance(routeObj.distance)}} <span v-if="routeObj.time != null">({{formatRouteTime(routeObj.time, routeObj.mode)}})</span></dd>

<template v-if="routeObj.ascent != null">
<dt>Climb/drop</dt>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/ui/coordinates.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { Point } from "facilmap-types";
import copyToClipboard from "copy-to-clipboard";
import { formatCoordinates } from "facilmap-utils";
import { formatCoordinates, formatElevation } from "facilmap-utils";
import Icon from "./icon.vue";
import { computed } from "vue";
import { useToasts } from "./toasts/toasts.vue";
Expand Down Expand Up @@ -34,7 +34,7 @@
<Icon icon="copy" alt="Copy to clipboard"></Icon>
</button>
<span v-if="props.ele != null" v-tooltip="'Elevation'">
({{props.ele}}&#x202F;m)
({{formatElevation(props.ele)}})
</span>
</span>
</template>
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/lib/components/ui/elevation-stats.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { LineWithTrackPoints, RouteWithTrackPoints } from "facilmap-client";
import { createElevationStats } from "../../utils/heightgraph";
import Icon from "./icon.vue";
import { numberKeys, round } from "facilmap-utils";
import { formatAscentDescent, formatDistance, numberKeys } from "facilmap-utils";
import { computed, ref } from "vue";
import Popover from "./popover.vue";
import vTooltip from "../../utils/tooltip";
Expand All @@ -22,9 +22,9 @@
</script>

<template>
<span class="fm-elevation-stats">
<span class="fm-elevation-stats" v-if="route.ascent != null && route.descent != null">
<span>
<Icon icon="triangle-top" alt="Ascent"></Icon> {{route.ascent}}&#x202F;m / <Icon icon="triangle-bottom" alt="Descent"></Icon> {{route.descent}}&#x202F;m
<Icon icon="triangle-top" alt="Ascent"></Icon> {{formatAscentDescent(route.ascent)}} / <Icon icon="triangle-bottom" alt="Descent"></Icon> {{formatAscentDescent(route.descent)}}
</span>

<span ref="statsButtonContainerRef">
Expand All @@ -46,14 +46,14 @@
>
<dl class="row">
<dt class="col-6">Total ascent</dt>
<dd class="col-6">{{route.ascent}}&#x202F;m</dd>
<dd class="col-6">{{formatAscentDescent(route.ascent)}}</dd>

<dt class="col-6">Total descent</dt>
<dd class="col-6">{{route.descent}}&#x202F;m</dd>
<dd class="col-6">{{formatAscentDescent(route.descent)}}</dd>

<template v-for="stat in statsArr" :key="stat.i">
<dt class="col-6">{{stat.i == 0 ? '0%' : stat.i < 0 ? "≤ "+stat.i+"%" : "≥ "+stat.i+"%"}}</dt>
<dd class="col-6">{{round(stat.distance, 2)}}&#x202F;km</dd>
<dd class="col-6">{{formatDistance(stat.distance)}}</dd>
</template>
</dl>
</Popover>
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/lib/components/ui/toasts/toasts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,6 @@
<style lang="scss">
.fm-toast-container {
position: absolute;
}
.fm-toasts {
z-index: 10002;
z-index: 10002; /* Above .fm-leaflet-map-disabled-cover */
}
</style>
1 change: 1 addition & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"p-throttle": "^6.1.0",
"pg": "^8.11.3",
"sequelize": "^6.37.1",
"serialize-error": "^11.0.3",
"socket.io": "^4.7.4",
"string-similarity": "^4.0.4",
"strip-bom-buf": "^4.0.0",
Expand Down
14 changes: 8 additions & 6 deletions server/src/database/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Database from "./database.js";
import { cloneDeep, isEqual } from "lodash-es";
import type { PadModel } from "./pad";
import { arrayToAsyncIterator } from "../utils/streams";
import { getI18n } from "../i18n.js";

const ITEMS_PER_BATCH = 5000;

Expand Down Expand Up @@ -124,7 +125,7 @@ export default class DatabaseHelpers {
if(!types[object.typeId]) {
types[object.typeId] = await this._db.types.getType(padId, object.typeId);
if(types[object.typeId] == null)
throw new Error("Type "+object.typeId+" does not exist.");
throw new Error(getI18n().t("database.type-not-found-error", { typeId: object.typeId }));
}

const type = types[object.typeId];
Expand All @@ -145,7 +146,7 @@ export default class DatabaseHelpers {
return entry != null;
}

async _getPadObject<T>(type: string, padId: PadId, id: ID): Promise<T> {
async _getPadObject<T>(type: "Marker" | "Line" | "Type" | "View" | "History", padId: PadId, id: ID): Promise<T> {
const includeData = [ "Marker", "Line" ].includes(type);

const entry = await this._db._conn.model(type).findOne({
Expand All @@ -154,8 +155,9 @@ export default class DatabaseHelpers {
nest: true
});

if(entry == null)
throw new Error(type + " " + id + " of pad " + padId + " could not be found.");
if(entry == null) {
throw new Error(getI18n().t("database.object-not-found-in-pad-error", { type, id, padId }));
}

const data: any = entry.toJSON();

Expand Down Expand Up @@ -213,7 +215,7 @@ export default class DatabaseHelpers {
return result;
}

async _updatePadObject<T>(type: string, padId: PadId, objId: ID, data: any, _noHistory?: boolean): Promise<T> {
async _updatePadObject<T>(type: "Marker" | "Line" | "View" | "Type" | "History", padId: PadId, objId: ID, data: any, _noHistory?: boolean): Promise<T> {
const includeData = [ "Marker", "Line" ].includes(type);
const makeHistory = !_noHistory && [ "Marker", "Line", "View", "Type" ].includes(type);

Expand Down Expand Up @@ -241,7 +243,7 @@ export default class DatabaseHelpers {
return newObject;
}

async _deletePadObject<T>(type: string, padId: PadId, objId: ID): Promise<T> {
async _deletePadObject<T>(type: "Marker" | "Line" | "View" | "Type" | "History", padId: PadId, objId: ID): Promise<T> {
const includeData = [ "Marker", "Line" ].includes(type);
const makeHistory = [ "Marker", "Line", "View", "Type" ].includes(type);

Expand Down
5 changes: 3 additions & 2 deletions server/src/database/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Database from "./database.js";
import type { HistoryEntry, HistoryEntryAction, HistoryEntryCreate, HistoryEntryType, ID, PadData, PadId } from "facilmap-types";
import { createModel, getDefaultIdType, makeNotNullForeignKey } from "./helpers.js";
import { cloneDeep } from "lodash-es";
import { getI18n } from "../i18n.js";

interface HistoryModel extends Model<InferAttributes<HistoryModel>, InferCreationAttributes<HistoryModel>> {
id: CreationOptional<ID>;
Expand Down Expand Up @@ -118,12 +119,12 @@ export default class DatabaseHistory {

if(entry.type == "Pad") {
if (!entry.objectBefore) {
throw new Error("Old pad data not available.");
throw new Error(getI18n().t("database.old-pad-data-not-available-error"));
}
await this._db.pads.updatePadData(padId, entry.objectBefore);
return;
} else if (!["Marker", "Line", "View", "Type"].includes(entry.type)) {
throw new Error(`Unknown type "${entry.type}.`);
throw new Error(getI18n().t("database.unknown-type-error", { type: entry.type }));
}

const existsNow = await this._db.helpers._padObjectExists(entry.type, padId, entry.objectId);
Expand Down
9 changes: 5 additions & 4 deletions server/src/database/line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { PadModel } from "./pad";
import type { Point as GeoJsonPoint } from "geojson";
import type { TypeModel } from "./type";
import { getLineTemplate, resolveCreateLine, resolveUpdateLine } from "facilmap-utils";
import { getI18n } from "../i18n.js";

export type LineWithTrackPoints = Line & {
trackPoints: TrackPoint[];
Expand Down Expand Up @@ -80,9 +81,9 @@ export default class DatabaseLines {
minTwo: function(val: string) {
const routePoints = JSON.parse(val);
if(!Array.isArray(routePoints))
throw new Error("routePoints is not an array");
throw new Error(getI18n().t("database.route-points-not-an-array-error"));
if(routePoints.length < 2)
throw new Error("A line cannot have less than two route points.");
throw new Error(getI18n().t("database.route-points-less-than-two-points-error"));
}
}
},
Expand Down Expand Up @@ -206,7 +207,7 @@ export default class DatabaseLines {
async createLine(padId: PadId, data: Line<CRU.CREATE_VALIDATED>, trackPointsFromRoute?: Route): Promise<Line> {
const type = await this._db.types.getType(padId, data.typeId);
if (type.type !== "line") {
throw new Error(`Cannot use ${type.type} type for line.`);
throw new Error(getI18n().t("database.cannot-use-type-for-line-error", { type: type.type }));
}

const resolvedData = resolveCreateLine(data, type);
Expand All @@ -231,7 +232,7 @@ export default class DatabaseLines {

async _updateLine(originalLine: Line, data: Line<CRU.UPDATE_VALIDATED>, newType: Type, noHistory?: boolean, trackPointsFromRoute?: Route): Promise<Line> {
if (newType.type !== "line") {
throw new Error(`Cannot use ${newType.type} type for line.`);
throw new Error(getI18n().t("database.cannot-use-type-for-line-error", { type: newType.type }));
}

const update = resolveUpdateLine(originalLine, data, newType);
Expand Down
5 changes: 3 additions & 2 deletions server/src/database/marker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getElevationForPoint, resolveCreateMarker, resolveUpdateMarker } from "
import type { PadModel } from "./pad.js";
import type { Point as GeoJsonPoint } from "geojson";
import type { TypeModel } from "./type.js";
import { getI18n } from "../i18n.js";

export interface MarkerModel extends Model<InferAttributes<MarkerModel>, InferCreationAttributes<MarkerModel>> {
id: CreationOptional<ID>;
Expand Down Expand Up @@ -91,7 +92,7 @@ export default class DatabaseMarkers {
async createMarker(padId: PadId, data: Marker<CRU.CREATE_VALIDATED>): Promise<Marker> {
const type = await this._db.types.getType(padId, data.typeId);
if (type.type !== "marker") {
throw new Error(`Cannot use ${type.type} type for marker.`);
throw new Error(getI18n().t("database.cannot-use-type-for-marker-error", { type: type.type }));
}

const result = await this._db.helpers._createPadObject<Marker>("Marker", padId, resolveCreateMarker(data, type));
Expand All @@ -118,7 +119,7 @@ export default class DatabaseMarkers {

async _updateMarker(originalMarker: Marker, data: Marker<CRU.UPDATE_VALIDATED>, newType: Type, noHistory = false): Promise<Marker> {
if (newType.type !== "marker") {
throw new Error(`Cannot use ${newType.type} type for marker.`);
throw new Error(getI18n().t("database.cannot-use-type-for-marker-error", { type: newType.type }));
}

const update = resolveUpdateMarker(originalMarker, data, newType);
Expand Down
Loading

0 comments on commit dfc8570

Please sign in to comment.