();
const commonProps: ObjectProperty[] = [
- { key: 'name', title: 'Name', type: 'string' },
- { key: 'visible', title: 'Visible', type: 'boolean', groupable: true },
+ { key: 'name', title: t('planner.properties.name'), type: 'string' },
+ {
+ key: 'visible',
+ title: t('planner.properties.visible'),
+ type: 'boolean',
+ groupable: true,
+ },
];
const lineProps: ObjectProperty[] = [
...commonProps,
- { key: 'width', title: 'Line Width', type: 'number', groupable: true },
- { key: 'color', title: 'Color', type: 'color', groupable: true },
+ {
+ key: 'width',
+ title: t('planner.properties.width'),
+ type: 'number',
+ groupable: true,
+ },
+ {
+ key: 'color',
+ title: t('planner.properties.color'),
+ type: 'color',
+ groupable: true,
+ },
{
key: 'lineCap',
- title: 'Line Cap Style',
+ title: t('planner.properties.lineCap'),
type: 'select',
groupable: true,
options: [
{ value: undefined, title: '' },
- { value: 'butt', title: 'Butt' },
- { value: 'round', title: 'Round' },
- { value: 'square', title: 'Square' },
+ { value: 'butt', title: t('planner.properties.butt') },
+ { value: 'round', title: t('planner.properties.round') },
+ { value: 'square', title: t('planner.properties.square') },
],
},
{
key: 'lineJoin',
- title: 'Line Join Style',
+ title: t('planner.properties.lineJoin'),
type: 'select',
groupable: true,
options: [
{ value: undefined, title: '' },
- { value: 'miter', title: 'Miter' },
- { value: 'bevel', title: 'Bevel' },
- { value: 'round', title: 'Round' },
+ { value: 'miter', title: t('planner.properties.miter') },
+ { value: 'bevel', title: t('planner.properties.bevel') },
+ { value: 'round', title: t('planner.properties.round') },
],
},
- { key: 'closed', title: 'Closed', type: 'boolean', groupable: true },
+ {
+ key: 'closed',
+ title: t('planner.properties.closed'),
+ type: 'boolean',
+ groupable: true,
+ },
];
const objectTypeProperties: ObjectProperties[] = [
@@ -95,20 +118,20 @@ const objectTypeProperties: ObjectProperties[] = [
];
const currentLayer = computed(() =>
- props.layers.find((layer) => layer.active && layer.visible)
+ props.layers.find((layer) => layer.active && layer.visible),
);
// TODO multi edit
const selectedObject = computed(
- () => currentLayer.value?.contents?.filter((obj) => obj.selected)[0]
+ () => currentLayer.value?.contents?.filter((obj) => obj.selected)[0],
);
const applicableProperties = computed(
() =>
selectedObject.value &&
objectTypeProperties.find(
- (prop) => prop.type === selectedObject.value?.type
- )
+ (prop) => prop.type === selectedObject.value?.type,
+ ),
);
const updateProp = (prop: ObjectProperty, value: unknown) => {
@@ -119,7 +142,7 @@ const updateProp = (prop: ObjectProperty, value: unknown) => {
currentLayer.value!.id,
selectedObject.value!.id,
prop.key,
- value
+ value,
);
};
diff --git a/src/components/house-planner/PlannerSidebar.vue b/src/components/house-planner/PlannerSidebar.vue
index 239037e..af5bc15 100644
--- a/src/components/house-planner/PlannerSidebar.vue
+++ b/src/components/house-planner/PlannerSidebar.vue
@@ -3,13 +3,18 @@
diff --git a/src/i18n.ts b/src/i18n.ts
new file mode 100644
index 0000000..06e4d39
--- /dev/null
+++ b/src/i18n.ts
@@ -0,0 +1,12 @@
+import { createI18n } from 'vue-i18n';
+import en from '@/locales/en.json';
+
+const i18n = createI18n({
+ locale: 'en',
+ fallbackLocale: 'en',
+ globalInjection: true,
+ legacy: false,
+ messages: { en },
+});
+
+export default i18n;
diff --git a/src/locales/en.json b/src/locales/en.json
new file mode 100644
index 0000000..0b38a6b
--- /dev/null
+++ b/src/locales/en.json
@@ -0,0 +1,86 @@
+{
+ "login": {
+ "title": "Sign in to your account",
+ "submit": "Sign in",
+ "email": "Email address",
+ "password": "Password",
+ "logout": "Logout"
+ },
+ "common": {
+ "user": "User",
+ "users": "Users",
+ "actions": "Actions",
+ "back": "Go back",
+ "building": "Building",
+ "buildings": "Buildings",
+ "group": "Group",
+ "groups": "Groups",
+ "floor": "Floor",
+ "floors": "Floors",
+ "hide": "Hide",
+ "show": "Show",
+ "open": "Open",
+ "close": "Close",
+ "storage": "Storage",
+ "storages": "Storages",
+ "set": "Set",
+ "storageSet": "Storage set",
+ "openMenu": "Open menu",
+ "closeMenu": "Close menu"
+ },
+ "dashboard": {
+ "title": "Dashboard",
+ "expiringSoon": "Expiring soon",
+ "intro": "Hello, {name}"
+ },
+ "buildings": {
+ "editPlans": "Edit floor plans",
+ "editPlan": "Edit floor plan",
+ "floorIn": "Floor {floor} in {building}",
+ "floor": "Floor {floor}",
+ "interactive": "interactive floor plan"
+ },
+ "planner": {
+ "choose": "Choose a floor to edit from the top left",
+ "status": {
+ "modified": "Modified",
+ "noChanges": "No changes",
+ "saving": "Saving...",
+ "saved": "Saved!",
+ "failed": "Failed to save!"
+ },
+ "panel": {
+ "open": "panel",
+ "layers": {
+ "title": "Layers"
+ },
+ "properties": {
+ "title": "Properties"
+ }
+ },
+ "properties": {
+ "name": "Name",
+ "visible": "Visible",
+ "width": "Line Width",
+ "color": "Color",
+ "lineCap": "Line Cap Style",
+ "butt": "Butt",
+ "round": "Round",
+ "square": "Square",
+ "lineJoin": "Line Join Style",
+ "miter": "Miter",
+ "bevel": "Bevel",
+ "closed": "Closed"
+ }
+ },
+ "storage": {
+ "selectRoom": "Select Room",
+ "selectStorageSet": "Select Storage / Set",
+ "selectStorage": "Select Storage",
+ "move": "Move storage",
+ "set": "set",
+ "add": "Add Storage",
+ "addSet": "Add Storage Set",
+ "storedItems": "Stored items"
+ }
+}
diff --git a/src/main.ts b/src/main.ts
index e51df65..e605bf0 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,11 +3,13 @@ import './style.scss';
import App from './App.vue';
import { createPinia } from 'pinia';
import router from './router';
+import i18n from './i18n';
const pinia = createPinia();
const app = createApp(App);
+app.use(i18n);
app.use(pinia);
app.use(router);
diff --git a/src/store/user.store.ts b/src/store/user.store.ts
index 1c06e21..0e53cc7 100644
--- a/src/store/user.store.ts
+++ b/src/store/user.store.ts
@@ -1,7 +1,7 @@
import { defineStore } from 'pinia';
import { User } from '../interfaces/user.interfaces';
import { useLocalStorage } from '@vueuse/core';
-import jwtDecode from 'jwt-decode';
+import { jwtDecode } from 'jwt-decode';
import { BACKEND_URL } from '../constants';
import jfetch from '../utils/jfetch';
@@ -53,7 +53,7 @@ export const useUserStore = defineStore('user', {
Authorization: `Basic ${header}`,
'Content-Type': 'application/json',
}),
- }
+ },
);
this.accessToken = tokenResponse.access_token;
diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue
index 4f4f13d..38d7249 100644
--- a/src/views/Dashboard.vue
+++ b/src/views/Dashboard.vue
@@ -1,12 +1,16 @@
- Dashboard
+ {{ $t('dashboard.title') }}
- Hello, {{ user.name }}
+ {{ $t('dashboard.intro', { name: user.name }) }}
Expiring soon
+ {{ $t('dashboard.expiringSoon') }}
+
- Buildings
+ {{ $t('common.buildings') }}
updateDocument(layers, rooms, boundingBox)
"
- @edited="status = 'Modified'"
+ @edited="status = 'modified'"
/>
- Choose a floor to edit from the top left
+ {{
+ $t('planner.choose')
+ }}
@@ -52,13 +52,13 @@ const route = useRoute();
const { buildings, floors } = storeToRefs(building);
const selectedBuildingId = ref
();
const selectedFloorId = ref();
-const status = ref('No changes');
+const status = ref('noChanges');
const plannerRef = ref>();
const currentFloor = computed(
() =>
selectedFloorId.value &&
- floors.value.find((floor) => floor.id === selectedFloorId.value)
+ floors.value.find((floor) => floor.id === selectedFloorId.value),
);
const floorPlan = computed(
() =>
@@ -67,7 +67,7 @@ const floorPlan = computed(
...defaultRoomData,
...JSON.parse(currentFloor.value.plan || '{}'),
id: selectedFloorId.value,
- })
+ }),
);
const buildingSelected = async (id: number) => {
@@ -99,7 +99,7 @@ const updateRooms = async (data: FloorDocument, rooms: Line[]) => {
const createdRooms = await building.upsertFloorRooms(
selectedBuildingId.value,
currentFloor.value.number,
- extractedRooms
+ extractedRooms,
);
if (createdRooms?.length) {
@@ -122,25 +122,25 @@ const updateRooms = async (data: FloorDocument, rooms: Line[]) => {
const updateDocument = async (
data: FloorDocument,
rooms: Line[],
- boundingBox?: Vec2Box
+ boundingBox?: Vec2Box,
) => {
if (
!selectedBuildingId.value ||
!selectedFloorId.value ||
selectedFloorId.value !== data.id ||
!currentFloor.value ||
- status.value === 'Saving...'
+ status.value === 'saving'
)
return;
- status.value = 'Saving...';
+ status.value = 'saving';
try {
data = await updateRooms(data, rooms);
// Prevent useless requests
const floorPlan = JSON.stringify({ ...data, boundingBox });
if (currentFloor.value.plan === floorPlan) {
- status.value = 'Saved!';
+ status.value = 'saved';
return;
}
@@ -149,12 +149,12 @@ const updateDocument = async (
currentFloor.value.number,
{
plan: floorPlan,
- }
+ },
);
- status.value = 'Saved!';
+ status.value = 'saved';
} catch (e) {
console.error(`Failed to save floor document: ${(e as Error).stack}`);
- status.value = 'Failed to save!';
+ status.value = 'failed';
}
};
diff --git a/src/views/Login.vue b/src/views/Login.vue
index ba00bcc..31d9dd2 100644
--- a/src/views/Login.vue
+++ b/src/views/Login.vue
@@ -1,13 +1,13 @@
- Sign in to your account
+ {{ $t('login.title') }}
-
+
diff --git a/src/views/building/BuildingView.vue b/src/views/building/BuildingView.vue
index b7fa1bc..a50d629 100644
--- a/src/views/building/BuildingView.vue
+++ b/src/views/building/BuildingView.vue
@@ -3,17 +3,17 @@
{{ building?.displayName }}
- {{
+ {{
building?.address
}}
@@ -124,11 +130,11 @@