feat: add i18next, move attribute labels
parent
4b3e7fc7a1
commit
b0ef7f86cb
|
@ -39,6 +39,7 @@
|
|||
"dompurify": "^2.3.4",
|
||||
"filesize": "^8.0.6",
|
||||
"history": "^5.1.0",
|
||||
"i18next": "^22.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^6.0.0",
|
||||
"marked": "^4.0.10",
|
||||
|
@ -48,6 +49,7 @@
|
|||
"sass": "^1.43.4",
|
||||
"sirv-cli": "^1.0.0",
|
||||
"sswr": "^1.3.1",
|
||||
"svelte-i18next": "^1.2.2",
|
||||
"svelte-navigator": "^3.1.5",
|
||||
"three": "^0.136.0",
|
||||
"upend": "../tools/upend_js",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import IconButton from "./utils/IconButton.svelte";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
import { i18n } from "../i18n";
|
||||
|
||||
export let entries: UpEntry[];
|
||||
export let type: UpType | undefined = undefined;
|
||||
|
@ -73,7 +74,7 @@
|
|||
{#if type.name != "HIER"}
|
||||
{type.label || type.name || "???"}
|
||||
{:else}
|
||||
Members
|
||||
{$i18n.t("Members")}
|
||||
{/if}
|
||||
</UpLink>
|
||||
{:else}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
import { deleteEntry, putEntityAttribute, putEntry } from "../lib/api";
|
||||
import Icon from "./utils/Icon.svelte";
|
||||
import BlobViewer from "./display/BlobViewer.svelte";
|
||||
import { i18n } from "../i18n";
|
||||
const dispatch = createEventDispatcher();
|
||||
const params = useParams();
|
||||
|
||||
|
@ -188,7 +189,7 @@
|
|||
}
|
||||
|
||||
async function deleteObject() {
|
||||
if (confirm(`Really delete "${identities.join(" | ")}"?`)) {
|
||||
if (confirm(`${$i18n.t("Really delete")} "${identities.join(" | ")}"?`)) {
|
||||
await deleteEntry(address);
|
||||
dispatch("close");
|
||||
}
|
||||
|
@ -230,7 +231,7 @@
|
|||
<div class="detail-col">
|
||||
{#if groups?.length || editable}
|
||||
<section class="groups labelborder">
|
||||
<header><h3>Groups</h3></header>
|
||||
<header><h3>{$i18n.t("Groups")}</h3></header>
|
||||
<div class="content">
|
||||
{#each groups as [entryAddress, address]}
|
||||
<div class="group">
|
||||
|
@ -282,7 +283,7 @@
|
|||
|
||||
{#if currentUntypedAttributes.length > 0 || editable}
|
||||
<AttributeView
|
||||
title="Other attributes"
|
||||
title={$i18n.t("Other attributes")}
|
||||
{editable}
|
||||
entries={currentUntypedAttributes}
|
||||
on:change={onChange}
|
||||
|
@ -291,7 +292,9 @@
|
|||
|
||||
{#if currentBacklinks.length > 0}
|
||||
<AttributeView
|
||||
title={`Referred to (${$entity.backlinks.length})`}
|
||||
title={`${$i18n.t("Referred to")} (${
|
||||
$entity.backlinks.length
|
||||
})`}
|
||||
entries={currentBacklinks}
|
||||
reverse
|
||||
on:change={onChange}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import Icon from "../../utils/Icon.svelte";
|
||||
import Selector from "../../utils/Selector.svelte";
|
||||
import Spinner from "../../utils/Spinner.svelte";
|
||||
import { i18n } from "../../../i18n";
|
||||
|
||||
export let address: string;
|
||||
export let detail: boolean;
|
||||
|
@ -204,7 +205,9 @@
|
|||
});
|
||||
|
||||
try {
|
||||
const peaksReq = await fetch(`${API_URL}/thumb/${address}?mime=audio&type=json`);
|
||||
const peaksReq = await fetch(
|
||||
`${API_URL}/thumb/${address}?mime=audio&type=json`
|
||||
);
|
||||
const peaks = await peaksReq.json();
|
||||
wavesurfer.load(`${API_URL}/raw/${address}`, peaks.data);
|
||||
} catch (e) {
|
||||
|
@ -213,7 +216,9 @@
|
|||
if (
|
||||
(entity.get("FILE_SIZE") || 0) < 20_000_000 ||
|
||||
confirm(
|
||||
"File is large (>20 MiB) and UpEnd failed to load waveform from server. Generating the waveform locally may slow down your browser. Do you wish to proceed anyway?"
|
||||
$i18n.t(
|
||||
"File is large (>20 MiB) and UpEnd failed to load waveform from server. Generating the waveform locally may slow down your browser. Do you wish to proceed anyway?"
|
||||
)
|
||||
)
|
||||
) {
|
||||
console.warn(
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import { defaultEntitySort, entityValueSort } from "../../util/sort";
|
||||
import { attributeLabels } from "../../util/labels";
|
||||
import { formatDuration } from "../../util/fragments/time";
|
||||
import { i18n } from "../../i18n";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let columns: string | undefined = undefined;
|
||||
|
@ -49,7 +50,7 @@
|
|||
newEntryValue = undefined;
|
||||
}
|
||||
async function removeEntry(address: string) {
|
||||
if (confirm("Are you sure you want to remove the attribute?")) {
|
||||
if (confirm($i18n.t("Are you sure you want to remove the attribute?"))) {
|
||||
dispatch("change", { type: "delete", address } as AttributeChange);
|
||||
}
|
||||
}
|
||||
|
@ -144,9 +145,9 @@
|
|||
|
||||
// Formatting & Display
|
||||
const COLUMN_LABELS: { [key: string]: string } = {
|
||||
entity: "Entity",
|
||||
attribute: "Attribute",
|
||||
value: "Value",
|
||||
entity: $i18n.t("Entity"),
|
||||
attribute: $i18n.t("Attribute"),
|
||||
value: $i18n.t("Value"),
|
||||
};
|
||||
|
||||
function formatValue(value: string | number, attribute: string): string {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"attributes": {
|
||||
"FILE_MIME": "MIME type",
|
||||
"FILE_MTIME": "Last modified",
|
||||
"FILE_SIZE": "File size",
|
||||
"ADDED": "Added at",
|
||||
"LAST_VISITED": "Last visited at",
|
||||
"NUM_VISITED": "Times visited",
|
||||
"LBL": "Label",
|
||||
"IS": "Type",
|
||||
"TYPE": "Type ID",
|
||||
"MEDIA_DURATION": "Duration"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import i18next from "i18next";
|
||||
import { createI18nStore } from "svelte-i18next";
|
||||
import en from "./en.json";
|
||||
|
||||
i18next.init({
|
||||
lng: "en",
|
||||
resources: {
|
||||
en,
|
||||
},
|
||||
});
|
||||
|
||||
export const i18n = createI18nStore(i18next);
|
|
@ -1,23 +1,11 @@
|
|||
import { readable, type Readable } from "svelte/store";
|
||||
import { i18n } from "../i18n";
|
||||
import { derived, readable, type Readable } from "svelte/store";
|
||||
import { fetchAllAttributes } from "../lib/api";
|
||||
|
||||
const DEFAULT_ATTRIBUTE_LABELS = {
|
||||
FILE_MIME: "MIME type",
|
||||
FILE_MTIME: "Last modified",
|
||||
FILE_SIZE: "File size",
|
||||
ADDED: "Added at",
|
||||
LAST_VISITED: "Last visited at",
|
||||
NUM_VISITED: "Times visited",
|
||||
LBL: "Label",
|
||||
IS: "Type",
|
||||
TYPE: "Type ID",
|
||||
MEDIA_DURATION: "Duration",
|
||||
};
|
||||
|
||||
export const attributeLabels: Readable<{ [key: string]: string }> = readable(
|
||||
DEFAULT_ATTRIBUTE_LABELS,
|
||||
const databaseAttributeLabels: Readable<{ [key: string]: string }> = readable(
|
||||
{},
|
||||
(set) => {
|
||||
const result = Object.assign(DEFAULT_ATTRIBUTE_LABELS);
|
||||
const result = {};
|
||||
fetchAllAttributes().then((attributes) => {
|
||||
attributes.forEach((attribute) => {
|
||||
if (attribute.labels.length) {
|
||||
|
@ -28,3 +16,13 @@ export const attributeLabels: Readable<{ [key: string]: string }> = readable(
|
|||
});
|
||||
}
|
||||
);
|
||||
|
||||
export const attributeLabels: Readable<{ [key: string]: string }> = derived(
|
||||
[i18n, databaseAttributeLabels],
|
||||
([i18n, attributeLabels]) => {
|
||||
const result = {};
|
||||
Object.assign(result, i18n.getResourceBundle(i18n.language, "attributes"));
|
||||
Object.assign(result, attributeLabels);
|
||||
return result;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import { query } from "../lib/entity";
|
||||
import { vaultInfo } from "../util/info";
|
||||
import { updateTitle } from "../util/title";
|
||||
import { i18n } from "../i18n";
|
||||
|
||||
const roots = (async () => {
|
||||
const data = await fetchRoots();
|
||||
|
@ -114,7 +115,7 @@
|
|||
</h1>
|
||||
|
||||
<section class="roots">
|
||||
<h2>Roots</h2>
|
||||
<h2>{$i18n.t("Roots")}</h2>
|
||||
{#await roots}
|
||||
<Spinner centered />
|
||||
{:then data}
|
||||
|
@ -133,7 +134,7 @@
|
|||
<div class="frecent">
|
||||
{#if frequent.length || $frequentQuery === undefined}
|
||||
<section class="frequent">
|
||||
<h2>Frequently visited</h2>
|
||||
<h2>{$i18n.t("Frequently visited")}</h2>
|
||||
{#if $frequentQuery == undefined}
|
||||
<Spinner centered />
|
||||
{:else}
|
||||
|
@ -147,7 +148,7 @@
|
|||
{/if}
|
||||
{#if recent.length || $recentQuery === undefined}
|
||||
<section class="recent">
|
||||
<h2>Recently visited</h2>
|
||||
<h2>{$i18n.t("Recently visited")}</h2>
|
||||
{#if $recentQuery == undefined}
|
||||
<Spinner centered />
|
||||
{:else}
|
||||
|
@ -163,7 +164,7 @@
|
|||
|
||||
{#if latest.length || $latestQuery === undefined}
|
||||
<section class="latest">
|
||||
<h2>Most recently added</h2>
|
||||
<h2>{$i18n.t("Most recently added")}</h2>
|
||||
{#if $latestQuery == undefined}
|
||||
<Spinner centered />
|
||||
{:else}
|
||||
|
@ -177,13 +178,14 @@
|
|||
{/if}
|
||||
|
||||
<div class="button store-button">
|
||||
<Link to="/store">View store statistics</Link>
|
||||
<Link to="/store">{$i18n.t("View store statistics")}</Link>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div>
|
||||
<strong>UpEnd</strong> - a database for the complex, the changing, and the
|
||||
indeterminate
|
||||
<strong>UpEnd</strong> - {$i18n.t(
|
||||
"a database for the complex, the changing, and the indeterminate"
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<a target="_blank" href="https://upend.dev">
|
||||
|
|
|
@ -32,6 +32,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime@npm:^7.17.2":
|
||||
version: 7.19.4
|
||||
resolution: "@babel/runtime@npm:7.19.4"
|
||||
dependencies:
|
||||
regenerator-runtime: ^0.13.4
|
||||
checksum: 66b7e3c13e9ee1d2c9397ea89144f29a875edee266a0eb2d9971be51b32fdbafc85808c7a45e011e6681899bb804b4e2ee2aed6dc07108dbbd6b11b6cc2afba6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@emotion/cache@npm:^11.4.0, @emotion/cache@npm:^11.7.1":
|
||||
version: 11.7.1
|
||||
resolution: "@emotion/cache@npm:11.7.1"
|
||||
|
@ -1943,6 +1952,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"i18next@npm:^22.0.2":
|
||||
version: 22.0.2
|
||||
resolution: "i18next@npm:22.0.2"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.17.2
|
||||
checksum: d779ea7f8e35ad8fd9d38521b670dab9440c6f51eab4347800058ee311a5e55abacac7e55cb1ff9f6898b4222a5f2aac72175f0dc1faeffbf3b4b37800f8f924
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iconv-lite@npm:^0.6.2":
|
||||
version: 0.6.3
|
||||
resolution: "iconv-lite@npm:0.6.3"
|
||||
|
@ -3589,6 +3607,16 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"svelte-i18next@npm:^1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "svelte-i18next@npm:1.2.2"
|
||||
peerDependencies:
|
||||
i18next: "*"
|
||||
svelte: "*"
|
||||
checksum: 24f9ed0f5f796124e075b39dc65a34fbcf625bfc6a26fdab15095f4e2c7c289ba5bf3d0c48ea644544376f9d9ffc1e523626f3cac219cd804ccffdcb28dff937
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"svelte-navigator@npm:^3.1.5":
|
||||
version: 3.1.5
|
||||
resolution: "svelte-navigator@npm:3.1.5"
|
||||
|
@ -3964,6 +3992,7 @@ __metadata:
|
|||
eslint-plugin-svelte3: ^4.0.0
|
||||
filesize: ^8.0.6
|
||||
history: ^5.1.0
|
||||
i18next: ^22.0.2
|
||||
lodash: ^4.17.21
|
||||
lru-cache: ^6.0.0
|
||||
marked: ^4.0.10
|
||||
|
@ -3975,6 +4004,7 @@ __metadata:
|
|||
sswr: ^1.3.1
|
||||
svelte: ^3.49.0
|
||||
svelte-check: ^2.8.0
|
||||
svelte-i18next: ^1.2.2
|
||||
svelte-navigator: ^3.1.5
|
||||
svelte-preprocess: ^4.10.7
|
||||
three: ^0.136.0
|
||||
|
|
Loading…
Reference in New Issue