Skip to content

Commit

Permalink
Merge pull request #295 from tonyaellie/improve-languages-support
Browse files Browse the repository at this point in the history
feat: improve languages support
  • Loading branch information
tonyaellie authored Oct 25, 2024
2 parents 3eb5ece + 1d5b62f commit d39d109
Show file tree
Hide file tree
Showing 18 changed files with 348 additions and 171 deletions.
6 changes: 3 additions & 3 deletions frontend/components/Item/CreateModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
v-model="form.name"
:trigger-focus="focused"
:autofocus="true"
label="Item Name"
:label="$t('components.item.create_modal.item_name')"
:max-length="255"
:min-length="1"
/>
<FormTextArea v-model="form.description" label="Item Description" :max-length="1000" />
<FormMultiselect v-model="form.labels" label="Labels" :items="labels ?? []" />
<FormTextArea v-model="form.description" :label="$t('components.item.create_modal.item_description')" :max-length="1000" />
<FormMultiselect v-model="form.labels" :label="$t('global.labels')" :items="labels ?? []" />

<div class="modal-action mb-6">
<div>
Expand Down
33 changes: 21 additions & 12 deletions frontend/components/Item/View/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
}"
>
<template v-if="typeof h === 'string'">{{ h }}</template>
<template v-else>{{ h.text }}</template>
<template v-else>{{ $t(h.text) }}</template>
<div
v-if="sortByProperty === h.value"
:class="`inline-flex ${sortByProperty === h.value ? '' : 'opacity-0'}`"
Expand Down Expand Up @@ -109,11 +109,11 @@
:checked="h.enabled"
@change="toggleHeader(h.value)"
/>
<label class="label-text" :for="h.value"> {{ h.text }} </label>
<label class="label-text" :for="h.value"> {{ $t(h.text) }} </label>
</li>
</ul>
</div>
<div class="hidden md:block">Rows per page</div>
<div class="hidden md:block">{{ $t("components.item.view.table.rows_per_page") }}</div>
<select v-model.number="pagination.rowsPerPage" class="select select-primary select-sm">
<option :value="10">10</option>
<option :value="25">25</option>
Expand All @@ -122,7 +122,7 @@
</select>
<div class="btn-group">
<button :disabled="!hasPrev" class="btn btn-sm" @click="prev()">«</button>
<button class="btn btn-sm">Page {{ pagination.page }}</button>
<button class="btn btn-sm">{{ $t("components.item.view.table.page") }} {{ pagination.page }}</button>
<button :disabled="!hasNext" class="btn btn-sm" @click="next()">»</button>
</div>
</div>
Expand All @@ -149,20 +149,29 @@
const preferences = useViewPreferences();
const defaultHeaders = [
{ text: "Name", value: "name", enabled: true, type: "name" },
{ text: "Quantity", value: "quantity", align: "center", enabled: true },
{ text: "Insured", value: "insured", align: "center", enabled: true, type: "boolean" },
{ text: "Price", value: "purchasePrice", align: "center", enabled: true, type: "price" },
{ text: "Location", value: "location", align: "center", enabled: false, type: "location" },
{ text: "Archived", value: "archived", align: "center", enabled: false, type: "boolean" },
{ text: "Created At", value: "createdAt", align: "center", enabled: false, type: "date" },
{ text: "Updated At", value: "updatedAt", align: "center", enabled: false, type: "date" },
{
text: "items.name", value: "name", enabled: true, type: "name"
},
{ text: "items.quantity", value: "quantity", align: "center", enabled: true },
{ text: "items.insured", value: "insured", align: "center", enabled: true, type: "boolean" },
{ text: "items.purchase_price", value: "purchasePrice", align: "center", enabled: true, type: "price" },
{ text: "items.location", value: "location", align: "center", enabled: false, type: "location" },
{ text: "items.archived", value: "archived", align: "center", enabled: false, type: "boolean" },
{ text: "items.created_at", value: "createdAt", align: "center", enabled: false, type: "date" },
{ text: "items.updated_at", value: "updatedAt", align: "center", enabled: false, type: "date" },
] satisfies TableHeader[];
const headers = ref<TableHeader[]>(
(preferences.value.tableHeaders ?? []).concat(
defaultHeaders.filter(h => !preferences.value.tableHeaders?.find(h2 => h2.value === h.value))
)
// this is a hack to make sure that any changes to the defaultHeaders are reflected in the preferences
.map(h => (
{
...defaultHeaders.find(h2 => h2.value === h.value) as TableHeader,
enabled: h.enabled
}
))
);
console.log(headers.value);
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/Label/CreateModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
v-model="form.name"
:trigger-focus="focused"
:autofocus="true"
label="Label Name"
:label="$t('components.label.create_modal.label_name')"
:max-length="255"
:min-length="1"
/>
<FormTextArea v-model="form.description" label="Label Description" :max-length="255" />
<FormTextArea v-model="form.description" :label="$t('components.label.create_modal.label_description')" :max-length="255" />
<div class="modal-action">
<div class="flex justify-center">
<BaseButton class="rounded-r-none" :loading="loading" type="submit"> {{ $t("global.create") }} </BaseButton>
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/Location/CreateModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
:trigger-focus="focused"
:autofocus="true"
:required="true"
label="Location Name"
:label="$t('components.location.create_modal.location_name')"
:max-length="255"
:min-length="1"
/>
<FormTextArea v-model="form.description" label="Location Description" :max-length="1000" />
<FormTextArea v-model="form.description" :label="$t('components.location.create_modal.location_description')" :max-length="1000" />
<LocationSelector v-model="form.parent" />
<div class="modal-action">
<div class="flex justify-center">
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/Location/Selector.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<FormAutocomplete2 v-if="locations" v-model="value" :items="locations" display="name" label="Parent Location">
<FormAutocomplete2 v-if="locations" v-model="value" :items="locations" display="name" :label="$t('components.location.selector.parent_location')">
<template #display="{ item, selected, active }">
<div>
<div class="flex w-full">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<dl class="sm:divide-y sm:divide-gray-300">
<div v-for="(detail, i) in details" :key="i" class="group py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium text-base-content">
{{ detail.name }}
{{ $t(detail.name) }}
</dt>
<dd class="text-start text-sm text-base-content sm:col-span-2">
<slot :name="detail.slot || detail.name" v-bind="{ detail }">
Expand Down
61 changes: 59 additions & 2 deletions frontend/composables/use-formatters.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { useI18n } from "vue-i18n";
import { type UseTimeAgoMessages, type UseTimeAgoUnitNamesDefault } from "@vueuse/core";

const cache = {
currency: "",
};
Expand Down Expand Up @@ -37,7 +40,61 @@ function ordinalIndicator(num: number) {
}
}

export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): string {
export function useLocaleTimeAgo(date: Date) {
const { t } = useI18n();

const I18N_MESSAGES: UseTimeAgoMessages<UseTimeAgoUnitNamesDefault> = {
justNow: t("components.global.date_time.just-now"),
past: (n) => (n.match(/\d/) ? t("components.global.date_time.ago", [n]) : n),
future: (n) => (n.match(/\d/) ? t("components.global.date_time.in", [n]) : n),
month: (n, past) =>
n === 1
? past
? t("components.global.date_time.last-month")
: t("components.global.date_time.next-month")
: `${n} ${t(`components.global.date_time.months`)}`,
year: (n, past) =>
n === 1
? past
? t("components.global.date_time.last-year")
: t("components.global.date_time.next-year")
: `${n} ${t(`components.global.date_time.years`)}`,
day: (n, past) =>
n === 1
? past
? t("components.global.date_time.yesterday")
: t("components.global.date_time.tomorrow")
: `${n} ${t(`components.global.date_time.days`)}`,
week: (n, past) =>
n === 1
? past
? t("components.global.date_time.last-week")
: t("components.global.date_time.next-week")
: `${n} ${t(`components.global.date_time.weeks`)}`,
hour: (n) => `${n} ${
n === 1 ? t("components.global.date_time.hour") : t("components.global.date_time.hours")
}`,
minute: (n) => `${n} ${
n === 1 ? t("components.global.date_time.minute") : t("components.global.date_time.minutes")
}`,
second: (n) => `${n} ${
n === 1
? t("components.global.date_time.second")
: t("components.global.date_time.seconds")
}`,
invalid: "",
};

return useTimeAgo(date, {
fullDateFormatter: (date: Date) => date.toLocaleDateString(),
messages: I18N_MESSAGES,
});
}

export function fmtDate(
value: string | Date,
fmt: DateTimeFormat = "human"
): string {
const months = [
"January",
"February",
Expand All @@ -64,7 +121,7 @@ export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): st

switch (fmt) {
case "relative":
return useTimeAgo(dt).value + useDateFormat(dt, " (YYYY-MM-DD)").value;
return useLocaleTimeAgo(dt).value + useDateFormat(dt, " (YYYY-MM-DD)").value;
case "long":
return useDateFormat(dt, "YYYY-MM-DD (dddd)").value;
case "short":
Expand Down
27 changes: 15 additions & 12 deletions frontend/layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@
{{ $t("global.create") }}
</label>
<ul tabindex="0" class="dropdown-content menu rounded-box bg-base-100 w-full p-2 shadow">
<li v-for="btn in dropdown" :key="btn.name">
<li v-for="btn in dropdown" :key="btn.id">
<button @click="btn.action">
{{ btn.name }}
{{ btn.name.value }}
</button>
</li>
</ul>
Expand All @@ -81,7 +81,7 @@
}"
>
<component :is="n.icon" class="mr-4 size-6" />
{{ n.name }}
{{ n.name.value }}
</NuxtLink>
</li>
</ul>
Expand Down Expand Up @@ -135,19 +135,22 @@
const dropdown = [
{
name: "Item / Asset",
id: 0,
name: computed(() => t("menu.create_item")),
action: () => {
modals.item = true;
},
},
{
name: "Location",
id: 1,
name: computed(() => t("menu.create_location")),
action: () => {
modals.location = true;
},
},
{
name: "Label",
id: 2,
name: computed(() => t("menu.create_label")),
action: () => {
modals.label = true;
},
Expand All @@ -168,42 +171,42 @@
icon: MdiHome,
active: computed(() => route.path === "/home"),
id: 0,
name: t("menu.home"),
name: computed(() => t("menu.home")),
to: "/home",
},
{
icon: MdiFileTree,
id: 1,
active: computed(() => route.path === "/locations"),
name: t("menu.locations"),
name: computed(() => t("menu.locations")),
to: "/locations",
},
{
icon: MdiMagnify,
id: 2,
active: computed(() => route.path === "/items"),
name: t("menu.search"),
name: computed(() => t("menu.search")),
to: "/items",
},
{
icon: MdiWrench,
id: 3,
active: computed(() => route.path === "/maintenance"),
name: t("menu.maintenance"),
name: computed(() => t("menu.maintenance")),
to: "/maintenance",
},
{
icon: MdiAccount,
id: 4,
active: computed(() => route.path === "/profile"),
name: t("menu.profile"),
name: computed(() => t("menu.profile")),
to: "/profile",
},
{
icon: MdiCog,
id: 5,
active: computed(() => route.path === "/tools"),
name: t("menu.tools"),
name: computed(() => t("menu.tools")),
to: "/tools",
},
];
Expand Down
Loading

0 comments on commit d39d109

Please sign in to comment.