summaryrefslogtreecommitdiffstats
path: root/apps/projects/src/app/pages
diff options
context:
space:
mode:
Diffstat (limited to 'apps/projects/src/app/pages')
-rw-r--r--apps/projects/src/app/pages/_layout.svelte32
-rw-r--r--apps/projects/src/app/pages/data.svelte34
-rw-r--r--apps/projects/src/app/pages/home.svelte27
-rw-r--r--apps/projects/src/app/pages/not-found.svelte5
-rw-r--r--apps/projects/src/app/pages/views/category-form/index.svelte12
-rw-r--r--apps/projects/src/app/pages/views/data-table-paginator.svelte30
-rw-r--r--apps/projects/src/app/pages/views/entry-form/index.svelte13
-rw-r--r--apps/projects/src/app/pages/views/entry-form/sections/category.svelte11
-rw-r--r--apps/projects/src/app/pages/views/entry-form/sections/date-time.svelte233
-rw-r--r--apps/projects/src/app/pages/views/entry-form/sections/labels.svelte9
-rw-r--r--apps/projects/src/app/pages/views/settings-categories-tile.svelte21
-rw-r--r--apps/projects/src/app/pages/views/settings-labels-tile.svelte19
12 files changed, 231 insertions, 215 deletions
diff --git a/apps/projects/src/app/pages/_layout.svelte b/apps/projects/src/app/pages/_layout.svelte
index 3d632ae..fb34593 100644
--- a/apps/projects/src/app/pages/_layout.svelte
+++ b/apps/projects/src/app/pages/_layout.svelte
@@ -2,18 +2,27 @@
import {onMount} from "svelte";
import {location, link} from "svelte-spa-router";
import {logout_user} from "$app/lib/services/user-service";
- import {random_string, switch_theme} from "$shared/lib/helpers";
+ import {random_string} from "$shared/lib/helpers";
import {get_session_data} from "$shared/lib/session";
import ProfileModal from "$app/pages/views/profile-modal.svelte";
import {Menu, MenuItem, MenuItemSeparator} from "$shared/components/menu";
import Button from "$shared/components/button.svelte";
import {IconNames} from "$shared/lib/configuration";
+ import LL from "$app/lib/i18n/i18n-svelte";
+ import BlowoutToolbelt from "$shared/components/blowout-toolbelt.svelte";
+ import {currentLocale} from "$app/lib/stores/locale";
let ProfileModalFunctions = {};
let showUserMenu = false;
let userMenuTriggerNode;
const userMenuId = "__menu_" + random_string(3);
- const username = get_session_data().profile.username;
+ const username = get_session_data()?.profile.username;
+
+ function toolbelt_change(event) {
+ if (event.detail.name === "locale") {
+ currentLocale.set(event.detail.value);
+ }
+ }
onMount(() => {
userMenuTriggerNode = document.getElementById("open-user-menu");
@@ -21,6 +30,7 @@
</script>
<ProfileModal bind:functions={ProfileModalFunctions}/>
+<BlowoutToolbelt on:change={toolbelt_change}/>
<nav class="container max-width-xl@md width-fit-content@md width-100% max-width-none margin-y-xs@md margin-bottom-xs block@md position-relative@md position-absolute bottom-unset@md bottom-0">
<div class="tabs-nav-v2 justify-between">
@@ -28,17 +38,17 @@
<div class="tab-v2">
<a href="/home"
use:link
- class="tabs-nav-v2__item {($location === '/' || $location.startsWith('/home')) ? 'tabs-nav-v2__item--selected' : ''}">Home</a>
+ class="tabs-nav-v2__item {($location === '/' || $location.startsWith('/home')) ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.home()}</a>
</div>
<div class="tab-v2">
<a href="/data"
use:link
- class="tabs-nav-v2__item {$location.startsWith('/data') ? 'tabs-nav-v2__item--selected' : ''}">Data</a>
+ class="tabs-nav-v2__item {$location.startsWith('/data') ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.data()}</a>
</div>
<div class="tab-v2">
<a href="/settings"
use:link
- class="tabs-nav-v2__item {$location.startsWith('/settings') ? 'tabs-nav-v2__item--selected' : ''}">Settings</a>
+ class="tabs-nav-v2__item {$location.startsWith('/settings') ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.settings()}</a>
</div>
</div>
<div class="tab-v2 padding-x-sm">
@@ -51,7 +61,7 @@
icon_width="2rem"
icon_height="2rem"
icon_right_aligned="true"
- title="Toggle user menu"
+ title="{$LL.nav.usermenu.toggleTitle()}"
aria-controls="{userMenuId}"
/>
<Menu bind:show="{showUserMenu}"
@@ -59,14 +69,12 @@
id="{userMenuId}">
<div slot="options">
<MenuItem on:click={() => ProfileModalFunctions.open()}>
- <span title="Administrate your profile">Profile</span>
- </MenuItem>
- <MenuItem on:click={() => switch_theme()}>
- <span title="Change between a dark and light theme">Switch theme</span>
+ <span title="{$LL.nav.usermenu.profileTitle()}">{$LL.nav.usermenu.profile()}</span>
</MenuItem>
<MenuItemSeparator/>
- <MenuItem danger="true" on:click={() => logout_user()}>
- <span title="Log out of your profile">Log out</span>
+ <MenuItem danger="true"
+ on:click={() => logout_user()}>
+ <span title="{$LL.nav.usermenu.logoutTitle()}">{$LL.nav.usermenu.logout()}</span>
</MenuItem>
</div>
</Menu>
diff --git a/apps/projects/src/app/pages/data.svelte b/apps/projects/src/app/pages/data.svelte
index 070b98b..190c641 100644
--- a/apps/projects/src/app/pages/data.svelte
+++ b/apps/projects/src/app/pages/data.svelte
@@ -12,6 +12,7 @@
import {delete_time_entry, get_time_entries, get_time_entry} from "$shared/lib/api/time-entry";
import {seconds_to_hour_minute_string, is_guid, move_focus, unwrap_date_time_from_entry} from "$shared/lib/helpers";
import Button from "$shared/components/button.svelte";
+ import LL from "$app/lib/i18n/i18n-svelte";
let pageCount = 1;
let page = 1;
@@ -41,7 +42,10 @@
function set_duration_summary_string() {
if (entries.length > 0) {
- durationSummary = `Showing ${entries.length} ${entries.length === 1 ? "entry" : "entries"}, totalling in ${seconds_to_hour_minute_string(secondsLogged)}`;
+ durationSummary = $LL.data.durationSummary({
+ entryCountString: `${entries.length} ${entries.length === 1 ? $LL.data.entry() : $LL.data.entries()}`,
+ totalHourMin: seconds_to_hour_minute_string(secondsLogged)
+ });
} else {
durationSummary = "";
}
@@ -61,7 +65,7 @@
date: date_time.start_date,
start: date_time.start_time,
stop: date_time.stop_time,
- durationString: date_time.duration.hours + "h" + date_time.duration.minutes + "m",
+ durationString: date_time.duration.hours + $LL.data.hourSingleChar() + date_time.duration.minutes + $LL.data.minSingleChar(),
seconds: seconds,
category: entry.category,
labels: entry.labels,
@@ -126,7 +130,7 @@
}
async function handle_delete_entry_button_click(e, entryId) {
- if (confirm("Are you sure you want to delete this entry?")) {
+ if (confirm($LL.data.confirmDeleteEntry())) {
const response = await delete_time_entry(entryId);
if (response.ok) {
const indexOfEntry = entries.findIndex((c) => c.id === entryId);
@@ -180,7 +184,7 @@
});
</script>
-<Modal title="Edit entry"
+<Modal title="{$LL.data.editEntry()}"
bind:functions={EditEntryModal}
on:closed={() => EditEntryForm.reset()}>
<EntryForm bind:functions={EditEntryForm}
@@ -216,7 +220,7 @@
{#if currentTimespanFilter === TimeEntryQueryDuration.SPECIFIC_DATE}
<div class="flex items-baseline margin-bottom-xxxxs justify-between">
- <span class="text-sm color-contrast-medium margin-right-xs">Date:</span>
+ <span class="text-sm color-contrast-medium margin-right-xs">{$LL.data.date()}:</span>
<span class="text-sm">
<input type="date"
class="border-none padding-0 color-inherit bg-transparent"
@@ -227,7 +231,7 @@
{#if currentTimespanFilter === TimeEntryQueryDuration.DATE_RANGE}
<div class="flex items-baseline margin-bottom-xxxxs justify-between">
- <span class="text-sm color-contrast-medium margin-right-xs">From:</span>
+ <span class="text-sm color-contrast-medium margin-right-xs">{$LL.data.from()}:</span>
<span class="text-sm">
<input type="date"
class="border-none padding-0 color-inherit bg-transparent"
@@ -236,7 +240,7 @@
</div>
<div class="flex items-baseline margin-bottom-xxxxs justify-between">
- <span class="text-sm color-contrast-medium margin-right-xs">To:</span>
+ <span class="text-sm color-contrast-medium margin-right-xs">{$LL.data.to()}:</span>
<span class="text-sm">
<input type="date"
class="border-none padding-0 color-inherit bg-transparent"
@@ -249,13 +253,13 @@
<Button variant="subtle"
on:click={() => load_entries_with_filter(page)}
class="text-sm"
- text="Save"/>
+ text="{$LL.data.use()}"/>
</div>
</div>
<Layout>
<Tile class="{isLoading ? 'c-disabled loading' : ''}">
- <nav class="s-tabs text-sm">
+ <nav class="s-tabs text-sm hide">
<ul class="s-tabs__list">
<li><span class="s-tabs__link s-tabs__link--current">All (21)</span></li>
<li><span class="s-tabs__link">Published (19)</span></li>
@@ -280,7 +284,7 @@
<TCell type="th"
style="width: 100px">
<div class="flex items-center justify-between">
- <span>Date</span>
+ <span>{$LL.data.date()}</span>
<div class="date_filter_box_el cursor-pointer"
on:click={toggle_date_filter_box}>
<Icon name="{IconNames.funnel}"/>
@@ -291,21 +295,21 @@
<TCell type="th"
style="width: 100px">
<div class="flex items-center">
- <span>Duration</span>
+ <span>{$LL.data.duration()}</span>
</div>
</TCell>
<TCell type="th"
style="width: 100px;">
<div class="flex items-center">
- <span>Category</span>
+ <span>{$LL.data.category()}</span>
</div>
</TCell>
<TCell type="th"
style="width: 300px;">
<div class="flex items-center">
- <span>Description</span>
+ <span>{$LL.data.description()}</span>
</div>
</TCell>
<TCell type="th"
@@ -366,7 +370,7 @@
<TCell type="th"
thScope="row"
colspan="7">
- {isLoading ? "Loading..." : "No entries"}
+ {isLoading ? $LL.data.loading() + "..." : $LL.data.noEntries()}
</TCell>
</TRow>
{/if}
@@ -378,7 +382,7 @@
{#if durationSummary}
<small class={isLoading ? "c-disabled loading" : ""}>{durationSummary}</small>
{:else}
- <small class={isLoading ? "c-disabled loading" : ""}>No entries</small>
+ <small class={isLoading ? "c-disabled loading" : ""}>{$LL.data.noEntries()}</small>
{/if}
</p>
diff --git a/apps/projects/src/app/pages/home.svelte b/apps/projects/src/app/pages/home.svelte
index 84d6728..33bb0d8 100644
--- a/apps/projects/src/app/pages/home.svelte
+++ b/apps/projects/src/app/pages/home.svelte
@@ -1,4 +1,5 @@
<script lang="ts">
+ import LL from "$app/lib/i18n/i18n-svelte";
import {delete_time_entry, get_time_entries, get_time_entry, update_time_entry} from "$shared/lib/api/time-entry";
import {IconNames, QueryKeys} from "$shared/lib/configuration";
import {TimeEntryDto} from "$shared/lib/models/TimeEntryDto";
@@ -18,7 +19,7 @@
let isLoading = false;
let EditEntryForm: any;
let timeEntries = [] as Array<TimeEntryDto>;
- let timeLoggedTodayString = "0h0m";
+ let timeLoggedTodayString = "0" + $LL.home.hourSingleChar() + "0" + $LL.home.minSingleChar();
const queryClient = useQueryClient();
const queryResult = useQuery(QueryKeys.entries, async () => await get_time_entries({
@@ -49,7 +50,7 @@
}
async function on_delete_entry_button_click(event, entryId: string) {
- if (confirm("Are you sure you want to delete this entry?")) {
+ if (confirm($LL.home.confirmDeleteEntry())) {
$delete_entry_mutation.mutate(entryId);
}
}
@@ -88,34 +89,34 @@
<Layout>
<div class="grid gap-md margin-top-xs flex-row@md items-start flex-column-reverse">
<Tile class="col">
- <h3 class="text-md padding-bottom-xxxs">New entry</h3>
+ <h3 class="text-md padding-bottom-xxxs">{$LL.home.newEntry()}</h3>
<EntryFrom bind:functions={EditEntryForm}/>
</Tile>
<div class="col grid gap-sm">
<Tile class="col-6@md col-12">
<p class="text-xxl">{timeLoggedTodayString}</p>
- <p class="text-xs margin-bottom-xxs">Logged time today</p>
+ <p class="text-xs margin-bottom-xxs">{$LL.home.loggedTimeToday()}</p>
<pre class="text-xxl">{currentTime}</pre>
- <p class="text-xs">Current time</p>
+ <p class="text-xs">{$LL.home.currentTime()}</p>
</Tile>
<Tile class="col-6@md col-12">
<Stopwatch on:create={on_create_from_stopwatch}>
<h3 slot="header"
- class="text-md">Stopwatch</h3>
+ class="text-md">{$LL.home.stopwatch()}</h3>
</Stopwatch>
</Tile>
<Tile class="col-12">
- <h3 class="text-md padding-bottom-xxxs">Today's entries</h3>
+ <h3 class="text-md padding-bottom-xxxs">{$LL.home.todayEntries()}</h3>
<div class="max-width-100% overflow-auto">
<Table class="width-100% text-sm">
<THead>
<TCell type="th"
class="text-left">
- <span>Category</span>
+ <span>{$LL.home.category()}</span>
</TCell>
<TCell type="th"
class="text-left">
- <span>Timespan</span>
+ <span>{$LL.home.timespan()}</span>
</TCell>
<TCell type="th"
class="text-right">
@@ -123,7 +124,7 @@
variant="reset"
icon_width="1.2rem"
icon_height="1.2rem"
- title="Refresh today's entries"
+ title="{$LL.home.refreshTodayEntries()}"
on:click={() => queryClient.invalidateQueries(QueryKeys.entries)}/>
</TCell>
</THead>
@@ -148,13 +149,13 @@
icon_width="1.2rem"
icon_height="1.2rem"
on:click={(e) => on_edit_entry_button_click(e, entry.id)}
- title="Edit entry"/>
+ title="{$LL.home.editEntry()}"/>
<Button icon="{IconNames.trash}"
variant="reset"
icon_width="1.2rem"
icon_height="1.2rem"
on:click={(e) => on_delete_entry_button_click(e, entry.id)}
- title="Delete entry"/>
+ title="{$LL.home.deleteEntry()}"/>
</TCell>
</TRow>
{/each}
@@ -163,7 +164,7 @@
<TCell type="th"
thScope="row"
colspan="7">
- {isLoading ? "Loading..." : "No entries today"}
+ {isLoading ? $LL.home.loading() + "..." : $LL.home.noEntriesToday()}
</TCell>
</TRow>
{/if}
diff --git a/apps/projects/src/app/pages/not-found.svelte b/apps/projects/src/app/pages/not-found.svelte
index 46d0d1d..8822e0e 100644
--- a/apps/projects/src/app/pages/not-found.svelte
+++ b/apps/projects/src/app/pages/not-found.svelte
@@ -1,4 +1,5 @@
<script>
+ import LL from "$app/lib/i18n/i18n-svelte";
import {link} from "svelte-spa-router";
</script>
@@ -18,7 +19,7 @@
<main>
<header>404</header>
- <p>Page not found!</p>
+ <p>{$LL.messages.pageNotFound()}</p>
<a use:link
- href="/">Go to front</a>
+ href="/">{$LL.messages.goToFrontpage()}</a>
</main>
diff --git a/apps/projects/src/app/pages/views/category-form/index.svelte b/apps/projects/src/app/pages/views/category-form/index.svelte
index e8c0f94..21024c3 100644
--- a/apps/projects/src/app/pages/views/category-form/index.svelte
+++ b/apps/projects/src/app/pages/views/category-form/index.svelte
@@ -1,9 +1,9 @@
<script lang="ts">
import Alert from "$shared/components/alert.svelte";
import Dropdown from "$shared/components/dropdown.svelte";
- import labels, {reload_labels, create_label_async} from "$app/lib/stores/labels";
+ import labels, {create_label_async} from "$app/lib/stores/labels";
import {generate_random_hex_color} from "$shared/lib/colors";
- import {get} from "svelte/store";
+ import LL from "$app/lib/i18n/i18n-svelte";
let LabelsDropdown;
@@ -106,7 +106,7 @@
<div class="grid gap-x-xs margin-bottom-sm">
<div class="col-10">
<label for="name"
- class="form-label margin-bottom-xxs">Name</label>
+ class="form-label margin-bottom-xxs">{$LL.views.categoryForm.name()}</label>
<input type="text"
class="form-control width-100%"
id="name"
@@ -117,7 +117,7 @@
</div>
<div class="col-2">
<label for="color"
- class="form-label margin-bottom-xxs">Color</label>
+ class="form-label margin-bottom-xxs">{$LL.views.categoryForm.color()}</label>
<input type="color"
class="form-control width-100%"
id="color"
@@ -130,10 +130,10 @@
</div>
<div class="margin-bottom-sm">
<label for="labels"
- class="form-label margin-bottom-xxs">Default labels</label>
+ class="form-label margin-bottom-xxs">{$LL.views.categoryForm.defaultLabels()}</label>
<Dropdown id="labels"
createable={true}
- placeholder="Search or create"
+ placeholder="{$LL.views.categoryForm.labelsPlaceholder()}"
entries={$labels}
multiple={true}
on_create_async={(name) => dough.fields.labels.create({name})}/>
diff --git a/apps/projects/src/app/pages/views/data-table-paginator.svelte b/apps/projects/src/app/pages/views/data-table-paginator.svelte
index 3d9834a..b2649eb 100644
--- a/apps/projects/src/app/pages/views/data-table-paginator.svelte
+++ b/apps/projects/src/app/pages/views/data-table-paginator.svelte
@@ -1,4 +1,5 @@
<script>
+ import LL from "$app/lib/i18n/i18n-svelte";
import {createEventDispatcher, onMount} from "svelte";
import {restrict_input_to_numbers} from "$shared/lib/helpers";
@@ -52,8 +53,8 @@
<button on:click={decrement}
class="reset pagination__item {canDecrement ? '' : 'c-disabled'}">
<svg class="icon icon--xs flip-x"
- viewBox="0 0 16 16"
- ><title>Go to previous page</title>
+ viewBox="0 0 16 16">
+ <title>{$LL.views.dataTablePaginator.goToPrevPage()}</title>
<polyline
points="6 2 12 8 6 14"
fill="none"
@@ -68,26 +69,23 @@
<li>
<span class="pagination__jumper flex items-center">
- <input
- aria-label="Page number"
- class="form-control"
- id="curr-page"
- type="text"
- on:change={handle_change}
- value={page}
+ <input aria-label="Page number"
+ class="form-control"
+ id="curr-page"
+ type="text"
+ on:change={handle_change}
+ value={page}
/>
- <em>of {pageCount}</em>
+ <em>{$LL.views.dataTablePaginator.of()} {pageCount}</em>
</span>
</li>
<li>
- <button
- on:click={increment}
- class="reset pagination__item {canIncrement ? '' : 'c-disabled'}"
- >
+ <button on:click={increment}
+ class="reset pagination__item {canIncrement ? '' : 'c-disabled'}">
<svg class="icon icon--xs"
- viewBox="0 0 16 16"
- ><title>Go to next page</title>
+ viewBox="0 0 16 16">
+ <title>{$LL.views.dataTablePaginator.goToNextPage()}</title>
<polyline
points="6 2 12 8 6 14"
fill="none"
diff --git a/apps/projects/src/app/pages/views/entry-form/index.svelte b/apps/projects/src/app/pages/views/entry-form/index.svelte
index cb974ed..cf3d173 100644
--- a/apps/projects/src/app/pages/views/entry-form/index.svelte
+++ b/apps/projects/src/app/pages/views/entry-form/index.svelte
@@ -1,4 +1,5 @@
<script lang="ts">
+ import LL from "$app/lib/i18n/i18n-svelte";
import {TimeEntryDto} from "$shared/lib/models/TimeEntryDto";
import {Temporal} from "@js-temporal/polyfill";
import {createEventDispatcher, onMount, onDestroy} from "svelte";
@@ -48,7 +49,7 @@
function description_is_valid() {
if (!description) {
- descriptionError = "Description is required";
+ descriptionError = $LL.views.entryForm.errDescriptionReq();
} else {
descriptionError = "";
}
@@ -97,7 +98,7 @@
functions.reset();
dispatch("updated", response.data);
} else {
- formError = "An error occured while updating the entry, try again soon";
+ formError = $LL.views.entryForm.entryUpdateError();
formIsLoading = false;
}
} else {
@@ -106,7 +107,7 @@
functions.reset();
dispatch("created");
} else {
- formError = "An error occured while creating the entry, try again soon";
+ formError = $LL.views.entryForm.entryCreateError();
formIsLoading = false;
}
}
@@ -175,14 +176,14 @@
<div class="margin-bottom-sm">
<Textarea class="width-100%"
id="description"
- label="Description"
+ label="{$LL.views.entryForm.description()}"
errorText="{descriptionError}"
bind:value={description}></Textarea>
</div>
<div class="flex flex-row justify-end gap-x-xs">
{#if entryId}
- <Button text="Reset"
+ <Button text="{$LL.views.entryForm.reset()}"
on:click={() => functions.reset()}
variant="subtle"
/>
@@ -190,7 +191,7 @@
<Button loading={formIsLoading}
type="submit"
variant="primary"
- text={entryId ? "Save" : "Create"}
+ text={entryId ? $LL.views.entryForm.save() : $LL.views.entryForm.create()}
/>
</div>
</form>
diff --git a/apps/projects/src/app/pages/views/entry-form/sections/category.svelte b/apps/projects/src/app/pages/views/entry-form/sections/category.svelte
index aac84be..f7af382 100644
--- a/apps/projects/src/app/pages/views/entry-form/sections/category.svelte
+++ b/apps/projects/src/app/pages/views/entry-form/sections/category.svelte
@@ -3,6 +3,7 @@
import Dropdown from "$shared/components/dropdown.svelte";
import {is_guid, move_focus} from "$shared/lib/helpers";
import categories, {reload_categories, create_category_async} from "$app/lib/stores/categories";
+ import LL from "$app/lib/i18n/i18n-svelte"
let categoriesError = "";
let loading = false;
@@ -12,7 +13,7 @@
function reset() {
DropdownExports.reset();
categoriesError = "";
- console.log("Reset category-part");
+ console.log($LL.views.entryForm.category._logReset());
}
async function on_create({name}) {
@@ -40,7 +41,7 @@
let isValid = true;
const category = get_selected();
if (!is_guid(category?.id)) {
- categoriesError = "Category is required";
+ categoriesError = $LL.views.entryForm.category.errisRequired();
isValid = false;
move_focus(document.getElementById("category-dropdown"));
} else {
@@ -60,15 +61,15 @@
<Dropdown
entries={$categories}
- label="Category"
+ label="{$LL.views.entryForm.category.category()}"
maxlength="50"
createable={true}
- placeholder="Search or create"
+ placeholder="{$LL.views.entryForm.category.placeholder()}"
id="category-dropdown"
loading={loading}
name="category-dropdown"
on_create_async={on_create}
- noResultsText="No categories available (Create a new one by searching for it)"
+ noResultsText="{$LL.views.entryForm.category.noResults()}"
errorText="{categoriesError}"
bind:this={DropdownExports}
/>
diff --git a/apps/projects/src/app/pages/views/entry-form/sections/date-time.svelte b/apps/projects/src/app/pages/views/entry-form/sections/date-time.svelte
index c91e014..47b06e3 100644
--- a/apps/projects/src/app/pages/views/entry-form/sections/date-time.svelte
+++ b/apps/projects/src/app/pages/views/entry-form/sections/date-time.svelte
@@ -1,131 +1,134 @@
<script lang="ts">
- import {Temporal} from "@js-temporal/polyfill";
+ import LL from "$app/lib/i18n/i18n-svelte";
+ import {Temporal} from "@js-temporal/polyfill";
- // TIME
- let fromTimeValue = "";
- let fromTimeError = "";
- let toTimeValue = "";
- let toTimeError = "";
+ // TIME
+ let fromTimeValue = "";
+ let fromTimeError = "";
+ let toTimeValue = "";
+ let toTimeError = "";
- function handle_from_time_changed(e) {
- fromTimeValue = e.target.value;
- if (fromTimeValue) {
- fromTimeError = "";
- }
- }
+ function handle_from_time_changed(e) {
+ fromTimeValue = e.target.value;
+ if (fromTimeValue) {
+ fromTimeError = "";
+ }
+ }
- function handle_to_time_changed(e) {
- toTimeValue = e.target.value;
- if (toTimeValue) {
- toTimeError = "";
- }
- }
+ function handle_to_time_changed(e) {
+ toTimeValue = e.target.value;
+ if (toTimeValue) {
+ toTimeError = "";
+ }
+ }
- // DATE
- let date = Temporal.Now.plainDateTimeISO().toString().substring(0, 10);
- let dateError = "";
+ // DATE
+ let date = Temporal.Now.plainDateTimeISO().toString().substring(0, 10);
+ let dateError = "";
- function is_valid() {
- let isValid = true;
- let focusIsSet = false;
- if (!date) {
- dateError = "Date is required";
- isValid = false;
- if (!focusIsSet) {
- document.getElementById("date")?.focus();
- focusIsSet = true;
- }
- } else {
- dateError = "";
- }
+ function is_valid() {
+ let isValid = true;
+ let focusIsSet = false;
+ if (!date) {
+ dateError = $LL.views.entryForm.dateTime.errDateIsRequired();
+ isValid = false;
+ if (!focusIsSet) {
+ document.getElementById("date")?.focus();
+ focusIsSet = true;
+ }
+ } else {
+ dateError = "";
+ }
- if (!fromTimeValue) {
- fromTimeError = "From is required";
- isValid = false;
- if (!focusIsSet) {
- document.getElementById("from")?.focus();
- focusIsSet = true;
- }
- } else if (toTimeValue && fromTimeValue > toTimeValue) {
- fromTimeError = "From can not be after To";
- isValid = false;
- if (!focusIsSet) {
- document.getElementById("from")?.focus();
- focusIsSet = true;
- }
- } else if (fromTimeValue === toTimeValue) {
- fromTimeError = "From and To can not be equal";
- isValid = false;
- if (!focusIsSet) {
- document.getElementById("from")?.focus();
- focusIsSet = true;
- }
- } else {
- fromTimeError = "";
- }
+ if (!fromTimeValue) {
+ fromTimeError = $LL.views.entryForm.dateTime.errFromIsRequired();
+ isValid = false;
+ if (!focusIsSet) {
+ document.getElementById("from")?.focus();
+ focusIsSet = true;
+ }
+ } else if (toTimeValue && fromTimeValue > toTimeValue) {
+ fromTimeError = $LL.views.entryForm.dateTime.errFromAfterTo();
+ isValid = false;
+ if (!focusIsSet) {
+ document.getElementById("from")?.focus();
+ focusIsSet = true;
+ }
+ } else if (fromTimeValue === toTimeValue) {
+ fromTimeError = $LL.views.entryForm.dateTime.errFromEqTo();
- if (!toTimeValue) {
- toTimeError = "To is required";
- isValid = false;
- if (!focusIsSet) {
- document.getElementById("to")?.focus();
- focusIsSet = true;
- }
- } else if (fromTimeValue && toTimeValue < fromTimeValue) {
- toTimeError = "To can not be before From";
- isValid = false;
- if (!focusIsSet) {
- document.getElementById("to")?.focus();
- focusIsSet = true;
- }
- } else {
- toTimeError = "";
- }
+ isValid = false;
+ if (!focusIsSet) {
+ document.getElementById("from")?.focus();
+ focusIsSet = true;
+ }
+ } else {
+ fromTimeError = "";
+ }
- return isValid;
- }
+ if (!toTimeValue) {
+ toTimeError = $LL.views.entryForm.dateTime.errToIsRequired();
+ isValid = false;
+ if (!focusIsSet) {
+ document.getElementById("to")?.focus();
+ focusIsSet = true;
+ }
+ } else if (fromTimeValue && toTimeValue < fromTimeValue) {
+ toTimeError = $LL.views.entryForm.dateTime.errToBeforeFrom();
+ isValid = false;
+ if (!focusIsSet) {
+ document.getElementById("to")?.focus();
+ focusIsSet = true;
+ }
+ } else {
+ toTimeError = "";
+ }
- export const functions = {
- get_from_time_value() {
- return fromTimeValue;
- },
- get_to_time_value() {
- return toTimeValue;
- },
- get_date() {
- return date;
- },
- is_valid,
- reset(focusDate = false) {
- fromTimeValue = "";
- toTimeValue = "";
- if (focusDate) {
- document.getElementById("date")?.focus();
- }
- },
- set_times(value) {
- console.log(value);
- fromTimeValue = value.from.toString().substring(0, 5);
- toTimeValue = value.to.toString().substring(0, 5);
- },
- set_date(new_date: Temporal.PlainDate) {
- date = new_date.toString();
- },
- set_values(values) {
- const currentTimeZone = Temporal.Now.timeZone().id;
- const startDate = Temporal.Instant.from(values.start);
- const stopDate = Temporal.Instant.from(values.stop);
- fromTimeValue = startDate.toZonedDateTimeISO(currentTimeZone).toPlainTime().toString().substring(0, 5);
- toTimeValue = stopDate.toZonedDateTimeISO(currentTimeZone).toPlainTime().toString().substring(0, 5);
- date = startDate.toZonedDateTimeISO(currentTimeZone).toPlainDate().toString();
- }
- };
+ return isValid;
+ }
+
+ export const functions = {
+ get_from_time_value() {
+ return fromTimeValue;
+ },
+ get_to_time_value() {
+ return toTimeValue;
+ },
+ get_date() {
+ return date;
+ },
+ is_valid,
+ reset(focusDate = false) {
+ fromTimeValue = "";
+ toTimeValue = "";
+ if (focusDate) {
+ document.getElementById("date")?.focus();
+ }
+ console.log($LL.views.entryForm.dateTime._logReset());
+ },
+ set_times(value) {
+ console.log(value);
+ fromTimeValue = value.from.toString().substring(0, 5);
+ toTimeValue = value.to.toString().substring(0, 5);
+ },
+ set_date(new_date: Temporal.PlainDate) {
+ date = new_date.toString();
+ },
+ set_values(values) {
+ const currentTimeZone = Temporal.Now.timeZone().id;
+ const startDate = Temporal.Instant.from(values.start);
+ const stopDate = Temporal.Instant.from(values.stop);
+ fromTimeValue = startDate.toZonedDateTimeISO(currentTimeZone).toPlainTime().toString().substring(0, 5);
+ toTimeValue = stopDate.toZonedDateTimeISO(currentTimeZone).toPlainTime().toString().substring(0, 5);
+ date = startDate.toZonedDateTimeISO(currentTimeZone).toPlainDate().toString();
+ }
+ };
</script>
<div class="grid gap-xs">
<div class="col-4">
<label for="date"
- class="form-label margin-bottom-xxs">Date</label>
+ class="form-label margin-bottom-xxs">{$LL.views.entryForm.dateTime.date()}</label>
<input type="date"
id="date"
class="form-control width-100%"
@@ -136,7 +139,7 @@
</div>
<div class="col-4">
<label for="from"
- class="form-label margin-bottom-xxs">From</label>
+ class="form-label margin-bottom-xxs">{$LL.views.entryForm.dateTime.from()}</label>
<input id="from"
class="form-control width-100%"
pattern="[0-9][0-9]:[0-9][0-9]"
@@ -150,7 +153,7 @@
</div>
<div class="col-4">
<label for="to"
- class="form-label margin-bottom-xxs">To</label>
+ class="form-label margin-bottom-xxs">{$LL.views.entryForm.dateTime.to()}</label>
<input id="to"
class="form-control width-100%"
pattern="[0-9][0-9]:[0-9][0-9]"
diff --git a/apps/projects/src/app/pages/views/entry-form/sections/labels.svelte b/apps/projects/src/app/pages/views/entry-form/sections/labels.svelte
index f0853cc..a6f324b 100644
--- a/apps/projects/src/app/pages/views/entry-form/sections/labels.svelte
+++ b/apps/projects/src/app/pages/views/entry-form/sections/labels.svelte
@@ -1,4 +1,5 @@
<script>
+ import LL from "$app/lib/i18n/i18n-svelte";
import {generate_random_hex_color} from "$shared/lib/colors";
import labels, {reload_labels, create_label_async} from "$app/lib/stores/labels";
import Dropdown from "$shared/components/dropdown.svelte";
@@ -9,7 +10,7 @@
function reset() {
DropdownExports.reset();
- console.log("Reset labels-part");
+ console.log($LL.views.entryForm.labels._logReset());
}
function get_selected() {
@@ -50,15 +51,15 @@
<Dropdown
entries={$labels}
- label="Labels"
+ label="{$LL.views.entryForm.labels.labels()}"
maxlength="50"
createable={true}
- placeholder="Search or create"
+ placeholder="{$LL.views.entryForm.labels.placeholder()}"
multiple="{true}"
id="labels-search"
name="labels-search"
on_create_async={on_create}
- noResultsText="No labels available (Create a new one by searching for it)"
+ noResultsText="{$LL.views.entryForm.labels.placeholder()}"
errorText="{labelsError}"
bind:this={DropdownExports}
{loading}
diff --git a/apps/projects/src/app/pages/views/settings-categories-tile.svelte b/apps/projects/src/app/pages/views/settings-categories-tile.svelte
index 890609a..8d2480f 100644
--- a/apps/projects/src/app/pages/views/settings-categories-tile.svelte
+++ b/apps/projects/src/app/pages/views/settings-categories-tile.svelte
@@ -8,6 +8,7 @@
import Button from "$shared/components/button.svelte";
import Tile from "$shared/components/tile.svelte";
import {Table, THead, TBody, TCell, TRow} from "$shared/components/table";
+ import LL from "$app/lib/i18n/i18n-svelte";
let is_loading = true;
let categories = [];
@@ -38,9 +39,7 @@
if (
row &&
row.dataset.id &&
- confirm(
- "Are you sure you want to delete this category?\nThis will delete all relating entries!"
- )
+ confirm($LL.views.settingsCategoriesTile.deleteAllConfirm())
) {
const response = await delete_time_category(row.dataset.id);
if (response.ok) {
@@ -56,14 +55,14 @@
</script>
<Tile class="col-6@md col-12 {is_loading ? 'c-disabled loading' : ''}">
- <h2 class="margin-bottom-xxs">Categories</h2>
+ <h2 class="margin-bottom-xxs">{$LL.views.settingsCategoriesTile.categories()}</h2>
{#if active_categories.length > 0 && archived_categories.length > 0}
<nav class="s-tabs text-sm">
<ul class="s-tabs__list">
<li><a class="s-tabs__link s-tabs__link--current"
- href="#0">Active ({active_categories.length})</a></li>
+ href="#0">{$LL.views.settingsCategoriesTile.active()} ({active_categories.length})</a></li>
<li><a class="s-tabs__link"
- href="#0">Archived ({archived_categories.length})</a></li>
+ href="#0">{$LL.views.settingsCategoriesTile.archived()} ({archived_categories.length})</a></li>
</ul>
</nav>
{/if}
@@ -72,11 +71,11 @@
<THead class="text-left">
<TCell type="th"
thScope="col">
- Name
+ {$LL.views.settingsCategoriesTile.name()}
</TCell>
<TCell type="th"
thScope="col">
- Color
+ {$LL.views.settingsCategoriesTile.color()}
</TCell>
<TCell type="th"
thScope="col"
@@ -102,13 +101,13 @@
class="hide"
icon_height="1.2rem"
on:click={handle_edit_category_click}
- title="Edit entry"/>
+ title="{$LL.views.settingsCategoriesTile.editEntry()}"/>
<Button icon="{IconNames.trash}"
variant="reset"
icon_width="1.2rem"
icon_height="1.2rem"
on:click={handle_delete_category_click}
- title="Delete entry"/>
+ title="{$LL.views.settingsCategoriesTile.deleteEntry()}"/>
</TCell>
</TRow>
@@ -117,7 +116,7 @@
<TRow>
<TCell type="th"
thScope="3">
- No categories
+ {$LL.views.settingsCategoriesTile.noCategories()}
</TCell>
</TRow>
{/if}
diff --git a/apps/projects/src/app/pages/views/settings-labels-tile.svelte b/apps/projects/src/app/pages/views/settings-labels-tile.svelte
index f59e233..59b5e30 100644
--- a/apps/projects/src/app/pages/views/settings-labels-tile.svelte
+++ b/apps/projects/src/app/pages/views/settings-labels-tile.svelte
@@ -5,6 +5,7 @@
import Button from "$shared/components/button.svelte";
import Tile from "$shared/components/tile.svelte";
import {Table, THead, TBody, TCell, TRow} from "$shared/components/table";
+ import LL from "$app/lib/i18n/i18n-svelte";
let is_loading = true;
@@ -25,9 +26,7 @@
if (
row &&
row.dataset.id &&
- confirm(
- "Are you sure you want to delete this label?\nIt will be removed from all related entries!"
- )
+ confirm($LL.views.settingsLabelsTile.deleteAllConfirm())
) {
await delete_label_async({id: row.dataset.id});
row.classList.add("d-none");
@@ -40,14 +39,14 @@
</script>
<Tile class="col-6@md col-12 {is_loading ? 'c-disabled loading' : ''}">
- <h2 class="margin-bottom-xxs">Labels</h2>
+ <h2 class="margin-bottom-xxs">{$LL.views.settingsLabelsTile.labels()}</h2>
{#if active_labels.length > 0 && archived_labels.length > 0}
<nav class="s-tabs text-sm">
<ul class="s-tabs__list">
<li><a class="s-tabs__link s-tabs__link--current"
- href="#0">Active ({active_labels.length})</a></li>
+ href="#0">{$LL.views.settingsLabelsTile.active()} ({active_labels.length})</a></li>
<li><a class="s-tabs__link"
- href="#0">Archived ({archived_labels.length})</a></li>
+ href="#0">{$LL.views.settingsLabelsTile.archived()} ({archived_labels.length})</a></li>
</ul>
</nav>
{/if}
@@ -56,11 +55,11 @@
<THead class="text-left">
<TCell type="th"
thScope="row">
- Name
+ {$LL.views.settingsLabelsTile.name()}
</TCell>
<TCell type="th"
thScope="row">
- Color
+ {$LL.views.settingsLabelsTile.color()}
</TCell>
<TCell type="th"
thScope="row"
@@ -87,13 +86,13 @@
class="hide"
icon_height="1.2rem"
on:click={handle_edit_label_click}
- title="Edit entry"/>
+ title="{$LL.views.settingsLabelsTile.editEntry()}"/>
<Button icon="{IconNames.trash}"
variant="reset"
icon_width="1.2rem"
icon_height="1.2rem"
on:click={handle_delete_label_click}
- title="Delete entry"/>
+ title="{$LL.views.settingsLabelsTile.deleteEntry()}"/>
</TCell>
</TRow>
{/each}