diff options
Diffstat (limited to 'apps/projects/src/app/pages')
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} |
