global: fix many localization related errors and issues

This commit is contained in:
Abdullah Atta
2024-11-08 10:24:50 +05:00
committed by Abdullah Atta
parent a240b0b3d7
commit 2417f8e233
48 changed files with 5865 additions and 5663 deletions

View File

@@ -140,7 +140,7 @@ export async function downloadAttachments(attachments) {
useAttachmentStore.getState().setDownloading({
current: 0,
total: 1,
message: `${strings.savingZipFile()}... ${strings.pleaseWait()}`,
message: strings.savingZipFile(),
groupId
});
// If all goes well, zip the notesnook-attachments folder in cache.
@@ -150,9 +150,7 @@ export async function downloadAttachments(attachments) {
groupId,
current: progress,
total: 1,
message: `${strings.savingZipFile()} (${(progress * 100).toFixed(
1
)}%)... ${strings.pleaseWait()}`
message: strings.savingZipFile((progress * 100).toFixed(1))
});
});
await zip(zipSourceFolder, zipOutputFile);

View File

@@ -336,10 +336,8 @@ export const AttachmentDialog = ({
onPress() {
if (!attachments) return;
presentDialog({
title: strings.doAction(
"attachment",
attachments.placeholders.length,
"download"
title: strings.doActions.download.attachment(
attachments.placeholders.length
),
positiveText: strings.network.download(),
positivePress: async () => {
@@ -390,10 +388,8 @@ export const AttachmentDialog = ({
onPress={() => {
if (!attachments) return;
presentDialog({
title: strings.doAction(
"attachment",
attachments.placeholders.length,
"download"
title: strings.doActions.download.attachment(
attachments.placeholders.length
),
positiveText: strings.network.download(),
positivePress: async () => {

View File

@@ -102,9 +102,8 @@ export const SelectionHeader = React.memo(
const deleteItem = async () => {
presentDialog({
title: strings.deleteItems(type as string, selectedItemsList.length),
paragraph: strings.deleteItemsConfirmation(
type as string,
title: strings.doActions.delete[type](selectedItemsList.length),
paragraph: strings.actionConfirmations.delete[type](
selectedItemsList.length
),
positiveText: strings.delete(),

View File

@@ -171,7 +171,7 @@ const ExportNotesSheet = ({
>
<DialogHeader
icon="export"
title={`${strings.export()} ${strings.notes(ids.length)}`}
title={strings.exportNotes(ids.length)}
/>
</View>

View File

@@ -57,7 +57,7 @@ const NewFeature = ({
}}
>
<Heading color={colors.secondary.heading} size={SIZE.md}>
{!version ? `${strings.newVersion()} ` : `v${version} `}Highlights 🎉
{strings.newVersionHighlights(version)}
</Heading>
<Seperator />

View File

@@ -121,8 +121,8 @@ const PublishNoteSheet = ({
}}
>
<DialogHeader
title={`${strings.publish()} ${strings.note()}`}
paragraph={strings.publishDesc()}
title={strings.publishNote()}
paragraph={strings.publishNoteDesc()}
/>
{publishing ? (

View File

@@ -255,8 +255,8 @@ export const useActions = ({
item.type === "color"
) {
presentDialog({
title: strings.deleteItem(item.type),
paragraph: strings.deleteItemConfirmation(item.type),
title: strings.doActions.delete[item.type](1),
paragraph: strings.actionConfirmations.delete[item.type](1),
positivePress: async () => {
if (item.type === "reminder") {
await db.reminders.remove(item.id);
@@ -304,8 +304,8 @@ export const useActions = ({
close();
await sleep(300);
presentDialog({
title: strings.delete(),
paragraph: strings.deleteItemsConfirmation(item.itemType, 1),
title: strings.doActions.delete[item.itemType](1),
paragraph: strings.actionConfirmations.delete[item.itemType](1),
positiveText: strings.delete(),
negativeText: strings.cancel(),
positivePress: async () => {
@@ -314,7 +314,7 @@ export const useActions = ({
Navigation.queueRoutesForUpdate();
useSelectionStore.getState().setSelectionMode(undefined);
ToastManager.show({
heading: strings.itemDeleted(1, item.itemType),
heading: strings.actions.deleted[item.itemType](1),
type: "success",
context: "local"
});
@@ -955,7 +955,7 @@ export const useActions = ({
id: "trash",
title:
item.type !== "notebook" && item.type !== "note"
? strings.doAction(item.type, 1, "delete")
? strings.doActions.delete[item.type](1)
: strings.moveToTrash(),
icon: "delete-outline",
type: "error",

View File

@@ -76,7 +76,7 @@ export const Search = ({ route, navigation }: NavigationProps<"Search">) => {
await results.item(0);
setResults(results);
if (results.placeholders?.length === 0) {
setSearchStatus(`${strings.noResultsFound(query)}`);
setSearchStatus(strings.noResultsFound(query));
} else {
setSearchStatus(undefined);
}
@@ -125,10 +125,8 @@ export const Search = ({ route, navigation }: NavigationProps<"Search">) => {
loading={loading}
placeholder={{
title: route.name,
paragraph:
searchStatus ||
`${strings.typeAKeywordToSearchIn(route.params?.title)}`,
loading: `${strings.searchingFor(currentQuery.current as string)}...`
paragraph: searchStatus || strings.searchInRoute(route.params?.title),
loading: strings.searchingFor(currentQuery.current as string)
}}
/>
</>

View File

@@ -153,7 +153,7 @@ const restoreBackup = async (options: {
if (path === ".nnbackup" || path === "attachments") continue;
updateProgress({
progress: `${strings.restoringBackup()}... (${count++}/${
progress: `${strings.restoringBackup()} (${count++}/${
extractedBackupFiles.length
})`
});
@@ -242,7 +242,7 @@ const restoreBackup = async (options: {
await db.transaction(async () => {
updateProgress({
progress: strings.restoringBackup() + "..."
progress: strings.restoringBackup()
});
await db.backup.import(backup, {
encryptionKey,

View File

@@ -351,9 +351,7 @@ export const settingsGroups: SettingSection[] = [
});
},
description(current) {
return `${strings.clearCacheDesc()}. ${strings.currentCacheSize(
`${current}`
)}`;
return strings.clearCacheDesc(current as number);
},
useHook: () => {
const [cacheSize, setCacheSize] = React.useState(0);
@@ -444,7 +442,7 @@ export const settingsGroups: SettingSection[] = [
}
updateProgress({
progress: `${strings.loggingOut()}... ${strings.pleaseWait()}`
progress: strings.loggingOut()
});
await db.user?.logout();

View File

@@ -33,7 +33,7 @@ import { strings } from "@notesnook/intl";
function confirmDeleteAllNotes(items, type, context) {
return new Promise((resolve) => {
presentDialog({
title: strings.doAction("type", items.length, "delete"),
title: strings.doActions.delete[type](items.length),
positiveText: strings.delete(),
negativeText: strings.cancel(),
positivePress: (_inputValue, value) => {
@@ -112,10 +112,10 @@ export const deleteItems = async (items, type, context) => {
}
} else if (type === "tag") {
presentDialog({
title: strings.deleteTags(ids.length),
title: strings.doActions.delete.tag(ids.length),
positiveText: strings.delete(),
negativeText: strings.cancel(),
paragraph: strings.deleteTagsConfirm(),
paragraph: strings.actionConfirmations.delete.tag(2),
positivePress: async () => {
await db.tags.remove(...ids);
useTagStore.getState().refresh();
@@ -128,7 +128,7 @@ export const deleteItems = async (items, type, context) => {
let deletedIds = [...ids];
if (type === "notebook" || type === "note") {
let message = strings.movedToTrash(type, ids.length);
let message = strings.actions.movedToTrash[type](ids.length);
ToastManager.show({
heading: message,
type: "success",

View File

@@ -73,8 +73,6 @@ test("creating a color shouldn't be possible on basic plan", async ({
await note?.contextMenu.newColor({ title: "red", color: "#ff0000" });
expect(
await app.toasts.waitForToast(
"Please upgrade your account to Pro to add colors."
)
await app.toasts.waitForToast("Upgrade to Notesnook Pro to add colors.")
).toBe(true);
});

View File

@@ -60,7 +60,7 @@ test("restore a note", async ({ page }) => {
const trashItem = await trash.findItem(NOTE.title);
await trashItem?.restore();
expect(await app.toasts.waitForToast("1 item restored")).toBe(true);
expect(await app.toasts.waitForToast("Item restored")).toBe(true);
await app.goToNotes();
await notes.waitForItem(NOTE.title);
const restoredNote = await notes.findNote(NOTE);

View File

@@ -86,7 +86,7 @@ test("delete a tag", async ({ page }) => {
await tag?.delete();
expect(await app.toasts.waitForToast("1 tag deleted")).toBe(true);
expect(await app.toasts.waitForToast("Tag deleted")).toBe(true);
expect(await tags?.findItem(TAG)).toBeUndefined();
});
@@ -235,9 +235,7 @@ test("creating more than 5 tags shouldn't be possible on basic plan", async ({
const result = await Promise.race([
tags.createItem({ title: "tag6" }),
app.toasts.waitForToast(
"Please upgrade your account to Pro to add more tags."
)
app.toasts.waitForToast("Upgrade to Notesnook Pro to create more tags.")
]);
expect(result).toBe(true);
});

View File

@@ -44,7 +44,6 @@ import { ReminderDialog } from "../dialogs/reminder-dialog";
import { Cipher, SerializedKey } from "@notesnook/crypto";
import { ChunkedStream } from "../utils/streams/chunked-stream";
import { isFeatureSupported } from "../utils/feature-check";
import { NNCrypto } from "../interfaces/nncrypto";
import { strings } from "@notesnook/intl";
export const CREATE_BUTTON_MAP = {
@@ -215,7 +214,7 @@ export async function restoreBackupFile(backupFile: File) {
} else {
const error = await TaskManager.startTask<Error | void>({
title: strings.restoringBackup(),
subtitle: `${strings.restoringBackupDesc()}...`,
subtitle: strings.restoringBackupDesc(),
type: "modal",
action: async (report) => {
let cachedPassword: string | undefined = undefined;
@@ -344,14 +343,14 @@ async function restoreWithProgress(
current: number;
}) => {
report({
text: `Restoring ${collection}...`,
text: strings.restoringCollection(collection),
current,
total
});
}
);
report({ text: `Restoring...` });
report({ text: strings.restoring() });
return restore(backup, password, key);
}
});

View File

@@ -48,16 +48,16 @@ async function moveNotesToTrash(ids: string[], confirm = true) {
await TaskManager.startTask({
type: "status",
id: "deleteNotes",
title: strings.deletingItems("note", items.length),
title: strings.inProgressActions.deleting.note(items.length),
action: async (report) => {
report({
text: `${strings.inProgressAction("note", items.length, "deleting")}...`
text: strings.inProgressActions.deleting.note(items.length)
});
await noteStore.delete(...items);
}
});
showToast("success", strings.movedToTrash("note", items.length));
showToast("success", strings.actions.movedToTrash.note(items.length));
}
async function moveNotebooksToTrash(ids: string[]) {
@@ -71,26 +71,22 @@ async function moveNotebooksToTrash(ids: string[]) {
await TaskManager.startTask({
type: "status",
id: "deleteNotebooks",
title: strings.deletingItems("notebook", ids.length),
title: strings.inProgressActions.deleting.notebook(ids.length),
action: async (report) => {
report({
text: `${strings.inProgressAction(
"notebook",
ids.length,
"deleting"
)}...`
text: strings.inProgressActions.deleting.notebook(ids.length)
});
await notebookStore.delete(...ids);
}
});
showToast("success", strings.movedToTrash("notebook", ids.length));
showToast("success", strings.actions.movedToTrash.notebook(ids.length));
}
async function deleteAttachments(ids: string[]) {
if (
!(await ConfirmDialog.show({
title: strings.doAction("attachment", ids.length, "permanentlyDelete"),
title: strings.doActions.permanentlyDelete.attachment(ids.length),
message: strings.irreverisibleAction(),
negativeButtonText: strings.no(),
positiveButtonText: strings.yes()
@@ -101,7 +97,7 @@ async function deleteAttachments(ids: string[]) {
await TaskManager.startTask({
type: "status",
id: "deleteAttachments",
title: strings.deletingItems("attachment", ids.length),
title: strings.inProgressActions.deleting.attachment(ids.length),
action: async (report) => {
for (let i = 0; i < ids.length; ++i) {
const id = ids[i];
@@ -109,11 +105,7 @@ async function deleteAttachments(ids: string[]) {
if (!attachment) continue;
report({
text: `${strings.inProgressAction(
"attachment",
ids.length,
"deleting"
)}...`,
text: strings.inProgressActions.deleting.attachment(ids.length),
current: i,
total: ids.length
});
@@ -121,7 +113,7 @@ async function deleteAttachments(ids: string[]) {
}
}
});
showToast("success", strings.deleted("attachment", ids.length));
showToast("success", strings.actions.deleted.attachment(ids.length));
}
async function moveRemindersToTrash(ids: string[]) {
@@ -133,20 +125,16 @@ async function moveRemindersToTrash(ids: string[]) {
await TaskManager.startTask({
type: "status",
id: "deleteReminders",
title: strings.deletingItems("reminder", ids.length),
title: strings.inProgressActions.deleting.reminder(ids.length),
action: async (report) => {
report({
text: `${strings.inProgressAction(
"reminder",
ids.length,
"deleting"
)}...`
text: strings.inProgressActions.deleting.reminder(ids.length)
});
await reminderStore.delete(...ids);
}
});
showToast("success", strings.deleted("reminder", ids.length));
showToast("success", strings.actions.deleted.reminder(ids.length));
}
async function deleteTags(ids: string[]) {
@@ -161,7 +149,7 @@ async function deleteTags(ids: string[]) {
title: "Deleting tags",
action: async (report) => {
report({
text: `${strings.inProgressAction("tag", ids.length, "deleting")}...`
text: strings.inProgressActions.deleting.tag(ids.length)
});
for (const id of ids) {
await db.tags.remove(id);
@@ -172,7 +160,7 @@ async function deleteTags(ids: string[]) {
}
});
showToast("success", strings.deleted("tag", ids.length));
showToast("success", strings.actions.deleted.tag(ids.length));
}
export const Multiselect = {

View File

@@ -1,63 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { db } from "./db";
import { store as notestore } from "../stores/note-store";
import { store as nbstore } from "../stores/notebook-store";
import { showToast } from "../utils/toast";
import { strings } from "@notesnook/intl";
async function showUnpinnedToast(itemId, itemType) {
const messageText = strings.action(itemType, 1, "unpinned");
const undoAction = async () => {
toast.hide();
if (itemType === "note") await notestore.pin(itemId);
else if (itemType === "notebook") await nbstore.pin(itemId);
};
let actions = [{ text: "Undo", onClick: undoAction }];
var toast = showToast("success", messageText, actions);
}
function showItemDeletedToast(item) {
const messageText = strings.action(item.type, 1, "deleted");
const undoAction = async () => {
toast.hide();
let trashItem = db.trash.all.find((i) => i.id === item.id);
if (!trashItem) return;
await db.trash.restore(trashItem.id);
nbstore.refresh();
notestore.refresh();
};
let actions = [{ text: "Undo", onClick: undoAction }];
var toast = showToast("success", messageText, actions);
}
async function showUndoableToast(message, onAction, onPermanentAction, onUndo) {
await onAction();
const timeoutId = setTimeout(onPermanentAction, 5000);
const undoAction = async () => {
clearTimeout(timeoutId);
toast.hide();
onUndo();
};
let actions = [{ text: strings.undo(), onClick: undoAction }];
var toast = showToast("success", message, actions);
}
export { showUnpinnedToast, showItemDeletedToast, showUndoableToast };

View File

@@ -303,7 +303,7 @@ const AttachmentMenuItems: (
icon: Rename.path,
onClick: async () => {
const newName = await PromptDialog.show({
title: strings.doAction("attachment", 1, "rename"),
title: strings.doActions.rename.attachment(1),
description: attachment.filename,
defaultValue: attachment.filename
});

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Button, Flex, Text } from "@theme-ui/components";
import { Flex, Text } from "@theme-ui/components";
import { SaveState, useEditorStore } from "../../stores/editor-store";
import { Loading, Saved, NotSaved } from "../icons";
import { useEditorConfig, useNoteStatistics } from "./manager";
@@ -98,8 +98,8 @@ function EditorFooter() {
variant="subBody"
sx={{ color: "paragraph" }}
>
{words.total + " " + strings.words()}
{words.selected ? ` (${words.selected} ${strings.selected()})` : ""}
{strings.totalWords(words.total)}
{words.selected ? ` (${strings.selectedWords(words.selected)})` : ""}
</Text>
{dateEdited > 0 ? (
<Text

View File

@@ -33,7 +33,7 @@ function EditorLoading({ text }: { text?: string }) {
>
<Loading color="accent" sx={{ mt: 2 }} />
<Text variant="body" mt={2} sx={{ textAlign: "center" }}>
{text || `${strings.loadingEditor()}. ${strings.pleaseWait()}...`}
{text || strings.loadingEditor()}
</Text>
</Flex>
);

View File

@@ -368,12 +368,12 @@ function NavigationMenu(props: NavigationMenuProps) {
{
type: "button",
key: "rename-color",
title: strings.doAction("color", 1, "rename"),
title: strings.renameColor(),
onClick: () => RenameColorDialog.show(color)
},
{
type: "button",
key: strings.doAction("color", 1, "remove"),
key: "remove-color",
title: strings.removeColor(),
onClick: async () => {
await db.colors.remove(color.id);
@@ -432,7 +432,7 @@ function NavigationMenu(props: NavigationMenuProps) {
{
type: "button",
key: "removeshortcut",
title: strings.doAction("shortcut", 1, "remove"),
title: strings.doActions.remove.shortcut(1),
onClick: async () => {
await db.shortcuts.remove(item.id);
refreshNavItems();

View File

@@ -244,7 +244,7 @@ function Note(props: NoteProps) {
data-test-id={`tag-item`}
key={tag.id}
variant="anchor"
title={`${strings.goTo()} #${tag.title}`}
title={strings.goToTag(tag.title)}
onClick={(e) => {
e.stopPropagation();
if (!tag.id)
@@ -721,7 +721,7 @@ function tagsMenuItems(ids: string[]): MenuItem[] {
{
type: "button",
key: "assign-tags",
title: `${strings.assignTo()}...`,
title: strings.assignTo(),
icon: Plus.path,
onClick: () => AddTagsDialog.show({ noteIds: ids })
},
@@ -815,7 +815,7 @@ async function copyNote(noteId: string, format: "md" | "txt") {
disableTemplate: true,
unlockVault: Vault.unlockVault
});
if (!result) throw new Error(`${strings.couldNotConvertNote(format)}.`);
if (!result) throw new Error(strings.couldNotConvertNote(format));
await navigator.clipboard.writeText(result);
showToast("success", strings.noteCopied());

View File

@@ -21,7 +21,6 @@ import { Button, Flex, Text } from "@theme-ui/components";
import { TipContext, useTip } from "../../hooks/use-tip";
import { Info, Sync } from "../icons";
import { useStore as useAppStore } from "../../stores/app-store";
import { toTitleCase } from "@notesnook/common";
import { strings } from "@notesnook/intl";
type PlaceholderProps = { context: TipContext; text?: string };
@@ -54,13 +53,13 @@ function Placeholder(props: PlaceholderProps) {
>
<Sync color="accent" size={12} sx={{ mr: "small" }} />
<Text variant="subBody" sx={{ fontSize: 10 }} color="accent">
{strings.syncingYour(context)}
{strings.syncingYourNotes()}
</Text>
</Flex>
<Text variant="subBody" sx={{ fontSize: "body", mt: 1 }}>
{toTitleCase(syncStatus.type || "sync")}ing {syncStatus.progress}{" "}
{strings.items()}
{strings.networkProgress(syncStatus.type || "sync")}{" "}
{syncStatus.progress} {strings.items()}
</Text>
</Flex>
);

View File

@@ -203,12 +203,12 @@ function PublishView(props: PublishViewProps) {
password
});
setPublishId(publishId);
showToast("success", strings.action("note", 1, "published"));
showToast("success", strings.actions.published.note(1));
} catch (e) {
console.error(e);
showToast(
"error",
`${strings.actionError("note", 1, "published")}: ${
`${strings.actionErrors.published.note(1)}: ${
(e as Error).message
}`
);
@@ -228,12 +228,12 @@ function PublishView(props: PublishViewProps) {
await unpublishNote(note.id);
setPublishId(undefined);
onClose(true);
showToast("success", strings.action("note", 1, "unpublished"));
showToast("success", strings.actions.unpublished.note(1));
} catch (e) {
console.error(e);
showToast(
"error",
`${strings.actionError("note", 1, "unpublished")}: ` +
`${strings.actionErrors.unpublished.note(1)}: ` +
(e as Error).message
);
} finally {

View File

@@ -152,7 +152,7 @@ const menuItems: (reminder: ReminderType, items?: string[]) => MenuItem[] = (
icon: Trash.path,
onClick: async () => {
ConfirmDialog.show({
title: strings.doAction("reminder", items.length, "delete"),
title: strings.doActions.delete.reminder(items.length),
message: strings.irreverisibleAction(),
positiveButtonText: strings.yes(),
negativeButtonText: strings.no()

View File

@@ -194,13 +194,11 @@ function statusToInfoText(status: UpdateStatus) {
return type === "checking"
? strings.checkingForUpdates()
: type === "downloading"
? `${Math.round(status.progress)}% ${strings.updating()}...`
? strings.updating(Math.round(status.progress))
: type === "completed"
? `v${
status.version
} ${strings.network.downloaded()} (${strings.restartRequired()})`
? strings.updateCompleted(status.version)
: type === "available"
? `v${status.version} ${strings.available()}`
? strings.updateNewVersionAvailable(status.version)
: "";
}

View File

@@ -65,7 +65,9 @@ export const AddNotebookDialog = DialogManager.register(
showToast(
"success",
strings.action("notebook", 1, props.edit ? "edited" : "created")
props.edit
? strings.actions.edited.notebook(1)
: strings.actions.created.notebook(1)
);
onClose(true);
}, [props.notebook?.id, props.edit, onClose, parentId]);

View File

@@ -191,7 +191,7 @@ export function CheckoutSideBar(props: SideBarProps) {
if (e instanceof Error)
showToast(
"error",
`${strings.couldNotActivateTrial()}. ${strings.pleaseTryAgain()} Error: ${
`${strings.couldNotActivateTrial()} ${strings.error()}: ${
e.message
}`
);

View File

@@ -26,7 +26,6 @@ import { db } from "../common/db";
import { getChangelog } from "../utils/version";
import { downloadUpdate } from "../utils/updater";
import { ErrorText } from "../components/error-text";
import { pluralize } from "@notesnook/common";
import { strings } from "@notesnook/intl";
type Check = { text: string; default?: boolean };
@@ -145,7 +144,7 @@ export const ConfirmDialog = DialogManager.register(function ConfirmDialog<
export function showMultiDeleteConfirmation(length: number) {
return ConfirmDialog.show({
title: strings.doAction("item", length, "delete"),
title: strings.doActions.delete.item(length),
message: strings.moveToTrashDesc(
db.settings.getTrashCleanupInterval() || 7
),
@@ -156,7 +155,7 @@ export function showMultiDeleteConfirmation(length: number) {
export function showMultiPermanentDeleteConfirmation(length: number) {
return ConfirmDialog.show({
title: strings.doAction("item", length, "permanentlyDelete"),
title: strings.doActions.permanentlyDelete.item(length),
message: strings.irreverisibleAction(),
positiveButtonText: strings.yes(),
negativeButtonText: strings.no()

View File

@@ -106,7 +106,7 @@ export const CreateTagDialog = {
)
return;
showToast("success", strings.action("tag", 1, "created"));
showToast("success", strings.actions.created.tag(1));
useTagStore.getState().refresh();
})
};
@@ -114,7 +114,7 @@ export const CreateTagDialog = {
export const EditTagDialog = {
show: (tag: Tag) =>
ItemDialog.show({
title: strings.doAction("tag", 1, "edit"),
title: strings.doActions.edit.tag(1),
subtitle: strings.editingTagDesc(tag.title),
defaultValue: tag.title
}).then(async (title) => {
@@ -126,7 +126,7 @@ export const EditTagDialog = {
}))
)
return;
showToast("success", strings.action("tag", 1, "edited"));
showToast("success", strings.actions.edited.tag(1));
await useTagStore.getState().refresh();
await useNoteStore.getState().refresh();
await useAppStore.getState().refreshNavItems();
@@ -148,7 +148,7 @@ export const RenameColorDialog = {
}))
)
return;
showToast("success", strings.action("color", 1, "renamed"));
showToast("success", strings.actions.renamed.color(1));
useAppStore.getState().refreshNavItems();
})
};

View File

@@ -55,13 +55,13 @@ export const MigrationDialog = DialogManager.register(function MigrationDialog(
EVENTS.migrationProgress,
({ collection, total, current }: MigrationProgressEvent) => {
task({
text: `${strings.processing()} ${collection}...`,
text: strings.processingCollection(collection),
current,
total
});
}
);
task({ text: `Processing...` });
task({ text: strings.processing() });
try {
await db.migrations.migrate();

View File

@@ -45,7 +45,6 @@ import {
TreeEnvironmentRef
} from "react-complex-tree";
import { FlexScrollContainer } from "../components/scroll-container";
import { pluralize } from "@notesnook/common";
import Field from "../components/field";
import { AddNotebookDialog } from "./add-notebook-dialog";
import { BaseDialogProps, DialogManager } from "../common/dialog-manager";
@@ -153,11 +152,13 @@ export const MoveNoteDialog = DialogManager.register(function MoveNoteDialog({
await noteStore.refresh();
await notebookStore.refresh();
const stringified = stringifySelected(selected);
if (stringified) {
const added = selected.filter((a) => a.new && a.op === "add").length;
const removed = selected.filter((a) => a.op === "remove").length;
if (added > 0 || removed > 0) {
showToast(
"success",
`${strings.notes(noteIds.length)} ${stringified}`
strings.assignedToNotebookMessage(noteIds.length, added, removed)
);
}
@@ -562,37 +563,3 @@ function selectSingle(topic: Notebook, array: NotebookReference[]) {
return selected;
}
function stringifySelected(suggestion: NotebookReference[]) {
const added = suggestion.filter((a) => a.new && a.op === "add");
// .map(resolveReference)
// .filter(Boolean);
const removed = suggestion.filter((a) => a.op === "remove");
// .map(resolveReference)
// .filter(Boolean);
if (!added.length && !removed.length) return;
const parts = [];
if (added.length > 0) parts.push(strings.addedToNotebook(added.length));
// if (added.length >= 1) parts.push(added[0]);
// if (added.length > 1) parts.push(`and ${added.length - 1} others`);
if (removed.length >= 1) {
if (parts.length > 0) parts.push("&");
parts.push(`removed from ${strings.removedFromNotebook(removed.length)}`);
}
// if (removed.length > 1) parts.push(`and ${removed.length - 1} others`);
return parts.join(" ") + ".";
}
// function resolveReference(ref: NotebookReference): string | undefined {
// const notebook = db.notebooks.notebook(ref.id);
// if (!notebook) return undefined;
// // if (ref.topic) {
// // return notebook.topics.topic(ref.topic)?._topic?.title;
// // } else {
// return notebook.title;
// // }
// }

View File

@@ -17,12 +17,16 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { createBackup, verifyAccount } from "../../common";
import { createBackup, verifyAccount, importBackup } from "../../common";
import { db } from "../../common/db";
import { exportNotes } from "../../common/export";
import { SettingsGroup } from "./types";
import { strings } from "@notesnook/intl";
import { useStore as useSettingStore } from "../../stores/setting-store";
import { useStore as useAppStore } from "../../stores/app-store";
import { useStore as useUserStore } from "../../stores/user-store";
import { desktop } from "../../common/desktop-bridge";
import { PATHS } from "@notesnook/desktop";
export const BackupExportSettings: SettingsGroup[] = [
{
@@ -51,6 +55,147 @@ export const BackupExportSettings: SettingsGroup[] = [
}
}
]
},
{
key: "restore-backup",
title: "Restore backup",
description: "Restore a backup file from your disk drive.",
components: [
{
type: "button",
title: "Restore",
action: async () => {
if (await importBackup()) {
await useAppStore.getState().refresh();
}
},
variant: "secondary"
}
]
},
{
key: "auto-backup",
title: "Automatic backup",
description: `Set the interval to automatically create a backup.
Note: these backups do not contain your attachments.`,
// isHidden: () => !isUserPremium(),
onStateChange: (listener) =>
useSettingStore.subscribe((s) => s.backupReminderOffset, listener),
components: [
{
type: "dropdown",
options: [
{ value: "0", title: "Never", premium: true },
{ value: "1", title: "Daily", premium: true },
{ value: "2", title: "Weekly", premium: true },
{ value: "3", title: "Monthly", premium: true }
],
selectedOption: () =>
useSettingStore.getState().backupReminderOffset.toString(),
onSelectionChanged: async (value) => {
const verified =
useSettingStore.getState().encryptBackups ||
(await verifyAccount());
if (verified)
useSettingStore
.getState()
.setBackupReminderOffset(parseInt(value));
}
}
]
},
{
key: "auto-backup-with-attachments",
title: "Automatic backup with attachments",
description: `Set the interval to automatically create a full backup with attachments.
NOTE: Creating a backup with attachments can take a while, and also fail completely. The app will try to resume/restart the backup in case of interruptions.`,
// isHidden: () => !isUserPremium(),
onStateChange: (listener) =>
useSettingStore.subscribe(
(s) => s.fullBackupReminderOffset,
listener
),
components: [
{
type: "dropdown",
options: [
{ value: "0", title: "Never", premium: true },
{ value: "1", title: "Weekly", premium: true },
{ value: "2", title: "Monthly", premium: true }
],
selectedOption: () =>
useSettingStore.getState().fullBackupReminderOffset.toString(),
onSelectionChanged: async (value) => {
const verified =
useSettingStore.getState().encryptBackups ||
(await verifyAccount());
if (verified)
useSettingStore
.getState()
.setFullBackupReminderOffset(parseInt(value));
}
}
]
},
{
key: "encrypt-backups",
title: "Backup encryption",
description: "Encrypt all backup files using your master key.",
isHidden: () => !useUserStore.getState().isLoggedIn,
onStateChange: (listener) => {
const subscriptions = [
useUserStore.subscribe((s) => s.isLoggedIn, listener),
useSettingStore.subscribe((s) => s.encryptBackups, listener)
];
return () => subscriptions.forEach((s) => s());
},
components: [
{
type: "toggle",
isToggled: () =>
!!useUserStore.getState().isLoggedIn &&
useSettingStore.getState().encryptBackups,
toggle: async () => {
const verified =
!useSettingStore.getState().encryptBackups ||
(await verifyAccount());
if (verified) useSettingStore.getState().toggleEncryptBackups();
}
}
]
},
{
key: "backup-directory",
title: "Backups directory",
description: "Select directory to store all backup files.",
isHidden: () => !IS_DESKTOP_APP,
components: [
{
type: "button",
title: "Select directory",
action: async () => {
const verified =
useSettingStore.getState().encryptBackups ||
(await verifyAccount());
if (!verified) return;
const backupStorageLocation =
useSettingStore.getState().backupStorageLocation ||
PATHS.backupsDirectory;
const location = await desktop?.integration.selectDirectory.query(
{
title: "Select where Notesnook should save backups",
defaultPath: backupStorageLocation
}
);
if (!location) return;
useSettingStore.getState().setBackupStorageLocation(location);
},
variant: "secondary"
}
]
}
]
},

View File

@@ -130,9 +130,9 @@ export const BehaviourSettings: SettingsGroup[] = [
useSettingStore.getState().trashCleanupInterval.toString(),
options: [
{ value: "1", title: strings.daily() },
{ value: "7", title: `7 ${strings.days()}` },
{ value: "30", title: `30 ${strings.days()}` },
{ value: "365", title: `365 ${strings.days()}` },
{ value: "7", title: strings.days(7) },
{ value: "30", title: strings.days(30) },
{ value: "365", title: strings.days(365) },
{ value: "-1", title: strings.never(), premium: true }
]
}

View File

@@ -171,12 +171,10 @@ export function ServersConfiguration() {
.then((r) => r.json() as Promise<VersionResponse>)
.catch(() => undefined);
if (!version)
throw new Error(
`${strings.couldNotConnectTo(server.title)} .`
);
throw new Error(strings.couldNotConnectTo(server.title));
if (version.id !== server.id)
throw new Error(
`${strings.incorrectServerUrl(url, server.title)}.`
strings.incorrectServerUrl(url, server.title)
);
if (!isServerCompatible(version.version))
throw new Error(

View File

@@ -137,7 +137,7 @@ function ThemesList() {
if (e instanceof Error)
showToast(
"error",
`${strings.failedToInstallTheme()}. Error: ` + e.message
`${strings.failedToInstallTheme()} ${strings.error()}: ` + e.message
);
} finally {
setIsApplying(false);

View File

@@ -45,7 +45,7 @@ class TrashStore extends BaseStore<TrashStore> {
restore = async (...ids: string[]) => {
const restored = await db.trash.restore(...ids);
if (restored === false) return;
showToast("success", strings.action("item", ids.length, "restored"));
showToast("success", strings.actions.restored.item(ids.length));
await this.get().refresh();
await appStore.refreshNavItems();
await noteStore.refresh();

View File

@@ -137,10 +137,7 @@ function useAuthenticateUser({
const user = await db.user.fetchUser();
setUser(user);
} catch (e) {
showToast(
"error",
`${strings.biometricsAuthFailed()}. ${strings.pleaseTryAgain()}.`
);
showToast("error", strings.biometricsAuthFailed());
openURL("/");
} finally {
setIsAuthenticating(false);
@@ -325,7 +322,7 @@ function RecoveryKeyMethod(props: BaseRecoveryComponentProps<"method:key">) {
title={strings.accountRecovery()}
subtitle={strings.accountRecoveryWithKey()}
loading={{
title: `${strings.network.downloading()} (${progress})`,
title: strings.network.downloading(progress),
subtitle: strings.keyRecoveryProgressDesc()
}}
onSubmit={async (form) => {
@@ -461,7 +458,7 @@ function NewPassword(props: BaseRecoveryComponentProps<"new">) {
title={strings.resetAccountPassword()}
subtitle={strings.accountPassDesc()}
loading={{
title: `${strings.resettingAccountPassword()} (${progress})`,
title: strings.resettingAccountPassword(progress),
subtitle: strings.resetPasswordWait()
}}
onSubmit={async (form) => {

View File

@@ -61,7 +61,9 @@ function Trash() {
if (e instanceof Error)
showToast(
"error",
`${strings.couldNotClearTrash()}. Error: ${e.message}`
`${strings.couldNotClearTrash()} ${strings.error()}: ${
e.message
}`
);
}
}

View File

@@ -38,20 +38,20 @@ function StatusBar({
const stickyRef = useRef(false);
const prevScroll = useRef(0);
const lastStickyChangeTime = useRef(0);
const [words, setWords] = useState(`0 ${strings.words()}`);
const [words, setWords] = useState(strings.totalWords(0));
const currentWords = useRef(words);
const statusBar = useRef({
set: setStatus,
updateWords: () => {
const editor = editors[tab.id];
if (!editor) return;
const words = getTotalWords(editor as Editor) + ` ${strings.words()}`;
const words = strings.totalWords(getTotalWords(editor as Editor));
if (currentWords.current === words) return;
setWords(words);
},
resetWords: () => {
currentWords.current = `0 ${strings.words()}`;
setWords(`0 ${strings.words()}`);
currentWords.current = strings.totalWords(0);
setWords(currentWords.current);
}
});

View File

@@ -1,2 +1,3 @@
.swc
locales
locales
generated/*.ts

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,7 @@
"@lingui/swc-plugin": "^4.0.10",
"@types/react": "^18.2.39",
"babel-plugin-macros": "^3.1.0",
"nodemon": "^3.1.7",
"react": "18.2.0",
"typescript": "5.5.3",
"vite": "^5.4.8",
@@ -877,9 +878,9 @@
}
},
"node_modules/@lingui/babel-plugin-extract-messages": {
"version": "4.11.4",
"resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-4.11.4.tgz",
"integrity": "sha512-7gUOsYJ4wIjv/0tGxAGiGpgWKCybFPP0tCQMz6baa9xcsk8Vp7Xmuf9og1AD6EMawjStibQsQyE6xaRnJgpoHg==",
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-4.14.0.tgz",
"integrity": "sha512-lLabYkUsiF0un4ezColFm9Yf23c+efPR/5DRM9cFwW9uZJ5ajN4Ic00dBxJK9HOpy6fpaANnaHFmrm4NScijvQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -887,22 +888,22 @@
}
},
"node_modules/@lingui/cli": {
"version": "4.11.4",
"resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-4.11.4.tgz",
"integrity": "sha512-PauBkvi++YkYAYq6w9MwkBmE6KiDE9wRh5DkN8yFPRcfj64vkE2l1HFENCqL/jg63kr8esOAiueD9+CtUGVyDg==",
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-4.14.0.tgz",
"integrity": "sha512-g9aJ76wpl6Fj06SEGiGnilAErEuZG6/woAU1HM81E0ZZ8ib1DF+cf81PJE+8Lwoxc0yMqY8qMScwhwcUhnR0aA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.21.0",
"@babel/generator": "^7.21.1",
"@babel/parser": "^7.21.2",
"@babel/parser": "^7.22.0",
"@babel/runtime": "^7.21.0",
"@babel/types": "^7.21.2",
"@lingui/babel-plugin-extract-messages": "4.11.4",
"@lingui/conf": "4.11.4",
"@lingui/core": "4.11.4",
"@lingui/format-po": "4.11.4",
"@lingui/message-utils": "4.11.4",
"@lingui/babel-plugin-extract-messages": "4.14.0",
"@lingui/conf": "4.14.0",
"@lingui/core": "4.14.0",
"@lingui/format-po": "4.14.0",
"@lingui/message-utils": "4.14.0",
"babel-plugin-macros": "^3.0.1",
"chalk": "^4.1.0",
"chokidar": "3.5.1",
@@ -930,6 +931,53 @@
"node": ">=16.0.0"
}
},
"node_modules/@lingui/cli/node_modules/@lingui/conf": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-4.14.0.tgz",
"integrity": "sha512-wHZ4s79wqPnROa3xEoUTNep7sjqwbDHCMLBhsHbcvk/3ACDKgm0TMvDnIRjMRwrPRsK98yxSmWaE+NKhT0Ggyw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.20.13",
"chalk": "^4.1.0",
"cosmiconfig": "^8.0.0",
"jest-validate": "^29.4.3",
"jiti": "^1.17.1",
"lodash.get": "^4.4.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@lingui/cli/node_modules/@lingui/core": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-4.14.0.tgz",
"integrity": "sha512-rsuBKG3mupWpfP5RYacufu0ToavrqgFPnEI/zOcuvMNL24IlZ38O2/P3POZCEA8XCyhON70FICy8xs3ZvQ+uWg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.20.13",
"@lingui/message-utils": "4.14.0",
"unraw": "^3.0.0"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@lingui/cli/node_modules/@lingui/message-utils": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-4.14.0.tgz",
"integrity": "sha512-izZod/6P2cXtqZt06r+VcbG3oCskPY8A1dVA8hyx0UZBCaufrZk6NgzCMYTMRXyOuXt6MafQyUfBJSrE4n3FIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@messageformat/parser": "^5.0.0",
"js-sha256": "^0.10.1"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@lingui/cli/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -1110,14 +1158,14 @@
}
},
"node_modules/@lingui/format-po": {
"version": "4.11.4",
"resolved": "https://registry.npmjs.org/@lingui/format-po/-/format-po-4.11.4.tgz",
"integrity": "sha512-PiWbTiiNgYZTFVuBHYirtAG98cDxrT0IwmSvETQk4YbaqCdn28/J7fRFZScsKqe8LmpnxX4EXZLs/R0MP2jLHA==",
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@lingui/format-po/-/format-po-4.14.0.tgz",
"integrity": "sha512-3Bmk9f7lRuBoZsBG5c5hq5ipgAqeux+nDVnAIXSfsp4f8jj+z+cHwW0xuHcW48mHQFwfcTGAYZcKnwhuwwut6Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@lingui/conf": "4.11.4",
"@lingui/message-utils": "4.11.4",
"@lingui/conf": "4.14.0",
"@lingui/message-utils": "4.14.0",
"date-fns": "^3.6.0",
"pofile": "^1.1.4"
},
@@ -1125,6 +1173,114 @@
"node": ">=16.0.0"
}
},
"node_modules/@lingui/format-po/node_modules/@lingui/conf": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-4.14.0.tgz",
"integrity": "sha512-wHZ4s79wqPnROa3xEoUTNep7sjqwbDHCMLBhsHbcvk/3ACDKgm0TMvDnIRjMRwrPRsK98yxSmWaE+NKhT0Ggyw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.20.13",
"chalk": "^4.1.0",
"cosmiconfig": "^8.0.0",
"jest-validate": "^29.4.3",
"jiti": "^1.17.1",
"lodash.get": "^4.4.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@lingui/format-po/node_modules/@lingui/message-utils": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-4.14.0.tgz",
"integrity": "sha512-izZod/6P2cXtqZt06r+VcbG3oCskPY8A1dVA8hyx0UZBCaufrZk6NgzCMYTMRXyOuXt6MafQyUfBJSrE4n3FIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@messageformat/parser": "^5.0.0",
"js-sha256": "^0.10.1"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@lingui/format-po/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@lingui/format-po/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/@lingui/format-po/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/@lingui/format-po/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"license": "MIT"
},
"node_modules/@lingui/format-po/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/@lingui/format-po/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@lingui/macro": {
"version": "4.11.4",
"resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-4.11.4.tgz",
@@ -1160,6 +1316,55 @@
"node": ">=16.0.0"
}
},
"node_modules/@lingui/react": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@lingui/react/-/react-4.13.0.tgz",
"integrity": "sha512-5remR9rVwosiiX/RnEWETHA8cpqQiP7U87OXXMPz67LuyG3XP8RP+ic75rVn284DHLHgpjDbauz7vYIz855ZoQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.13",
"@lingui/core": "4.13.0"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@lingui/react/node_modules/@lingui/core": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@lingui/core/-/core-4.13.0.tgz",
"integrity": "sha512-kRqQWeEVoqNrDtEdyHPWGsAHRStN8ObYc5a1gdyuBhoj1zaoUS/DMK5C7B1ZeTtj6rCCmZRs6d2tN12hsZ2zJA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.13",
"@lingui/message-utils": "4.13.0",
"unraw": "^3.0.0"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@lingui/react/node_modules/@lingui/message-utils": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-4.13.0.tgz",
"integrity": "sha512-tI/WBVZym+APwqk0O3xTaF0k+RQIv5E4PqGHdXqwbofycHly2C+izH+hg6UeNctc6jd19GRwqu/4ga9knkdAlQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@messageformat/parser": "^5.0.0",
"js-sha256": "^0.10.1"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@lingui/swc-plugin": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/@lingui/swc-plugin/-/swc-plugin-4.0.10.tgz",
@@ -1380,9 +1585,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
"integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.4.tgz",
"integrity": "sha512-jfUJrFct/hTA0XDM5p/htWKoNNTbDLY0KRwEt6pyOA6k2fmk0WVwl65PdUdJZgzGEHWx+49LilkcSaumQRyNQw==",
"cpu": [
"arm"
],
@@ -1394,9 +1599,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
"integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.4.tgz",
"integrity": "sha512-j4nrEO6nHU1nZUuCfRKoCcvh7PIywQPUCBa2UsootTHvTHIoIu2BzueInGJhhvQO/2FTRdNYpf63xsgEqH9IhA==",
"cpu": [
"arm64"
],
@@ -1408,9 +1613,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
"integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.4.tgz",
"integrity": "sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ==",
"cpu": [
"arm64"
],
@@ -1422,9 +1627,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
"integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.4.tgz",
"integrity": "sha512-N6oDBiZCBKlwYcsEPXGDE4g9RoxZLK6vT98M8111cW7VsVJFpNEqvJeIPfsCzbf0XEakPslh72X0gnlMi4Ddgg==",
"cpu": [
"x64"
],
@@ -1435,10 +1640,38 @@
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.4.tgz",
"integrity": "sha512-py5oNShCCjCyjWXCZNrRGRpjWsF0ic8f4ieBNra5buQz0O/U6mMXCpC1LvrHuhJsNPgRt36tSYMidGzZiJF6mw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.4.tgz",
"integrity": "sha512-L7VVVW9FCnTTp4i7KrmHeDsDvjB4++KOBENYtNYAiYl96jeBThFfhP6HVxL74v4SiZEVDH/1ILscR5U9S4ms4g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
"integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.4.tgz",
"integrity": "sha512-10ICosOwYChROdQoQo589N5idQIisxjaFE/PAnX2i0Zr84mY0k9zul1ArH0rnJ/fpgiqfu13TFZR5A5YJLOYZA==",
"cpu": [
"arm"
],
@@ -1450,9 +1683,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
"integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.4.tgz",
"integrity": "sha512-ySAfWs69LYC7QhRDZNKqNhz2UKN8LDfbKSMAEtoEI0jitwfAG2iZwVqGACJT+kfYvvz3/JgsLlcBP+WWoKCLcw==",
"cpu": [
"arm"
],
@@ -1464,9 +1697,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
"integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.4.tgz",
"integrity": "sha512-uHYJ0HNOI6pGEeZ/5mgm5arNVTI0nLlmrbdph+pGXpC9tFHFDQmDMOEqkmUObRfosJqpU8RliYoGz06qSdtcjg==",
"cpu": [
"arm64"
],
@@ -1478,9 +1711,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
"integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.4.tgz",
"integrity": "sha512-38yiWLemQf7aLHDgTg85fh3hW9stJ0Muk7+s6tIkSUOMmi4Xbv5pH/5Bofnsb6spIwD5FJiR+jg71f0CH5OzoA==",
"cpu": [
"arm64"
],
@@ -1492,9 +1725,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
"integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.4.tgz",
"integrity": "sha512-q73XUPnkwt9ZNF2xRS4fvneSuaHw2BXuV5rI4cw0fWYVIWIBeDZX7c7FWhFQPNTnE24172K30I+dViWRVD9TwA==",
"cpu": [
"ppc64"
],
@@ -1506,9 +1739,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
"integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.4.tgz",
"integrity": "sha512-Aie/TbmQi6UXokJqDZdmTJuZBCU3QBDA8oTKRGtd4ABi/nHgXICulfg1KI6n9/koDsiDbvHAiQO3YAUNa/7BCw==",
"cpu": [
"riscv64"
],
@@ -1520,9 +1753,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
"integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.4.tgz",
"integrity": "sha512-P8MPErVO/y8ohWSP9JY7lLQ8+YMHfTI4bAdtCi3pC2hTeqFJco2jYspzOzTUB8hwUWIIu1xwOrJE11nP+0JFAQ==",
"cpu": [
"s390x"
],
@@ -1534,9 +1767,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
"integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.4.tgz",
"integrity": "sha512-K03TljaaoPK5FOyNMZAAEmhlyO49LaE4qCsr0lYHUKyb6QacTNF9pnfPpXnFlFD3TXuFbFbz7tJ51FujUXkXYA==",
"cpu": [
"x64"
],
@@ -1548,9 +1781,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
"integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.4.tgz",
"integrity": "sha512-VJYl4xSl/wqG2D5xTYncVWW+26ICV4wubwN9Gs5NrqhJtayikwCXzPL8GDsLnaLU3WwhQ8W02IinYSFJfyo34Q==",
"cpu": [
"x64"
],
@@ -1562,9 +1795,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
"integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.4.tgz",
"integrity": "sha512-ku2GvtPwQfCqoPFIJCqZ8o7bJcj+Y54cZSr43hHca6jLwAiCbZdBUOrqE6y29QFajNAzzpIOwsckaTFmN6/8TA==",
"cpu": [
"arm64"
],
@@ -1576,9 +1809,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
"integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.4.tgz",
"integrity": "sha512-V3nCe+eTt/W6UYNr/wGvO1fLpHUrnlirlypZfKCT1fG6hWfqhPgQV/K/mRBXBpxc0eKLIF18pIOFVPh0mqHjlg==",
"cpu": [
"ia32"
],
@@ -1590,9 +1823,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
"integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.4.tgz",
"integrity": "sha512-LTw1Dfd0mBIEqUVCxbvTE/LLo+9ZxVC9k99v1v4ahg9Aak6FpqOfNu5kRkeTAn0wphoC4JU7No1/rL+bBCEwhg==",
"cpu": [
"x64"
],
@@ -2330,6 +2563,7 @@
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5",
"cosmiconfig": "^7.0.0",
@@ -3117,6 +3351,13 @@
}
]
},
"node_modules/ignore-by-default": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
"dev": true,
"license": "ISC"
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -3840,6 +4081,86 @@
"integrity": "sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==",
"dev": true
},
"node_modules/nodemon": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz",
"integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^3.5.2",
"debug": "^4",
"ignore-by-default": "^1.0.1",
"minimatch": "^3.1.2",
"pstree.remy": "^1.1.8",
"semver": "^7.5.3",
"simple-update-notifier": "^2.0.0",
"supports-color": "^5.5.0",
"touch": "^3.1.0",
"undefsafe": "^2.0.5"
},
"bin": {
"nodemon": "bin/nodemon.js"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/nodemon"
}
},
"node_modules/nodemon/node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/nodemon/node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/nodemon/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -4209,6 +4530,13 @@
"node": ">=16.0.0"
}
},
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
"dev": true,
"license": "MIT"
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -4357,38 +4685,21 @@
}
},
"node_modules/rollup": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
"version": "3.29.5",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz",
"integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.6"
},
"optional": true,
"peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"node": ">=14.18.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.24.0",
"@rollup/rollup-android-arm64": "4.24.0",
"@rollup/rollup-darwin-arm64": "4.24.0",
"@rollup/rollup-darwin-x64": "4.24.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
"@rollup/rollup-linux-arm-musleabihf": "4.24.0",
"@rollup/rollup-linux-arm64-gnu": "4.24.0",
"@rollup/rollup-linux-arm64-musl": "4.24.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
"@rollup/rollup-linux-riscv64-gnu": "4.24.0",
"@rollup/rollup-linux-s390x-gnu": "4.24.0",
"@rollup/rollup-linux-x64-gnu": "4.24.0",
"@rollup/rollup-linux-x64-musl": "4.24.0",
"@rollup/rollup-win32-arm64-msvc": "4.24.0",
"@rollup/rollup-win32-ia32-msvc": "4.24.0",
"@rollup/rollup-win32-x64-msvc": "4.24.0",
"fsevents": "~2.3.2"
}
},
@@ -4478,6 +4789,32 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
"node_modules/simple-update-notifier": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"semver": "^7.5.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/simple-update-notifier/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/source-map": {
"version": "0.8.0-beta.0",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
@@ -4628,6 +4965,16 @@
"node": ">=8.0"
}
},
"node_modules/touch": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
"dev": true,
"license": "ISC",
"bin": {
"nodetouch": "bin/nodetouch.js"
}
},
"node_modules/tr46": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
@@ -4675,6 +5022,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/undefsafe": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
"dev": true,
"license": "MIT"
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
@@ -5359,6 +5713,44 @@
"@esbuild/win32-x64": "0.21.5"
}
},
"node_modules/vite/node_modules/rollup": {
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.4.tgz",
"integrity": "sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.6"
},
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.24.4",
"@rollup/rollup-android-arm64": "4.24.4",
"@rollup/rollup-darwin-arm64": "4.24.4",
"@rollup/rollup-darwin-x64": "4.24.4",
"@rollup/rollup-freebsd-arm64": "4.24.4",
"@rollup/rollup-freebsd-x64": "4.24.4",
"@rollup/rollup-linux-arm-gnueabihf": "4.24.4",
"@rollup/rollup-linux-arm-musleabihf": "4.24.4",
"@rollup/rollup-linux-arm64-gnu": "4.24.4",
"@rollup/rollup-linux-arm64-musl": "4.24.4",
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.4",
"@rollup/rollup-linux-riscv64-gnu": "4.24.4",
"@rollup/rollup-linux-s390x-gnu": "4.24.4",
"@rollup/rollup-linux-x64-gnu": "4.24.4",
"@rollup/rollup-linux-x64-musl": "4.24.4",
"@rollup/rollup-win32-arm64-msvc": "4.24.4",
"@rollup/rollup-win32-ia32-msvc": "4.24.4",
"@rollup/rollup-win32-x64-msvc": "4.24.4",
"fsevents": "~2.3.2"
}
},
"node_modules/vscode-uri": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz",

View File

@@ -23,11 +23,11 @@
"url": "git://github.com/streetwriters/notesnook.git"
},
"scripts": {
"extract": "lingui extract",
"extract": "lingui extract --clean --overwrite",
"compile": "lingui compile --typescript",
"build-locale": "npm run extract && npm run compile",
"build-locale": "node scripts/generate-strings.mjs && npm run extract && npm run compile",
"build": "npm run build-locale && npx vite build && node scripts/postbuild.mjs",
"watch": "npx vite build --watch",
"watch": "nodemon --watch scripts/ --watch src --ext ts,mjs --exec \"npm run build\"",
"postinstall": "patch-package"
},
"devDependencies": {
@@ -36,6 +36,7 @@
"@lingui/swc-plugin": "^4.0.10",
"@types/react": "^18.2.39",
"babel-plugin-macros": "^3.1.0",
"nodemon": "^3.1.7",
"react": "18.2.0",
"typescript": "5.5.3",
"vite": "^5.4.8",

View File

@@ -0,0 +1,315 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { mkdirSync, writeFileSync } from "fs";
const DO_ACTIONS = [
{
action: "delete",
label: "Delete",
dataTypes: [
"note",
"item",
"reminder",
"notebook",
"tag",
"color",
"attachment"
]
},
{ action: "unpin", label: "Unpin", dataTypes: ["note", "notebook"] },
{ action: "pin", label: "Pin", dataTypes: ["note", "notebook"] },
{ action: "unpublish", label: "Unpublish", dataTypes: ["note"] },
{ action: "publish", label: "Publish", dataTypes: ["note"] },
{
action: "permanentlyDelete",
label: "Permanently delete",
dataTypes: ["attachment", "item"]
},
{
action: "restore",
label: "Restore",
dataTypes: ["note", "notebook"]
},
{
action: "edit",
label: "Edit",
dataTypes: ["tag", "notebook", "reminder"]
},
{
action: "rename",
label: "Rename",
dataTypes: ["attachment", "color", "tag"]
},
{
action: "remove",
label: "Remove",
dataTypes: ["shortcut", "color", "attachment"]
},
{
action: "download",
label: "Download",
dataTypes: ["attachment"]
}
];
const ACTIONS = [
{
action: "deleted",
label: "deleted",
dataTypes: ["attachment", "reminder", "tag", "note"]
},
{
action: "movedToTrash",
label: "moved to trash",
dataTypes: ["note", "notebook"]
},
{
action: "permanentlyDeleted",
label: "permanently deleted",
dataTypes: ["note", "notebook"]
},
{ action: "published", label: "published", dataTypes: ["note"] },
{
action: "restored",
label: "restored",
dataTypes: ["note", "notebook", "item"]
},
{
action: "edited",
label: "edited",
dataTypes: ["tag", "notebook"]
},
{
action: "created",
label: "created",
dataTypes: ["notebook", "tag", "shortcut"]
},
{
action: "renamed",
label: "renamed",
dataTypes: ["color"]
}
];
const ACTION_CONFIRMATIONS = [
{
action: "delete",
label: "delete",
dataTypes: [
"note",
"item",
"reminder",
"notebook",
"tag",
"color",
"attachment"
]
},
{
action: "permanentlyDelete",
label: "permanently delete",
dataTypes: ["note", "notebook"]
}
];
const ACTION_ERRORS = [
{
action: "unpublished",
label: "unpublished",
dataTypes: ["note"]
},
{
action: "published",
label: "published",
dataTypes: ["note"]
}
];
const IN_PROGRESS_ACTIONS = [
{
action: "deleting",
label: "Deleting",
dataTypes: ["note", "notebook", "attachment", "tag", "reminder"]
}
];
const DATA_TYPES = {
note: {
singular: `note`,
singularCamelCase: `Note`,
plural: `notes`,
pluralCamelCase: `Notes`
},
notebook: {
singular: `notebook`,
singularCamelCase: `Notebook`,
plural: `notebooks`,
pluralCamelCase: `Notebooks`
},
tag: {
singular: `tag`,
singularCamelCase: `Tag`,
plural: `tags`,
pluralCamelCase: `Tags`
},
reminder: {
singular: `reminder`,
singularCamelCase: `Reminder`,
plural: `reminders`,
pluralCamelCase: `Reminders`
},
color: {
singular: `color`,
singularCamelCase: `Color`,
plural: `colors`,
pluralCamelCase: `Colors`
},
attachment: {
singular: `attachment`,
singularCamelCase: `Attachment`,
plural: `attachments`,
pluralCamelCase: `Attachments`
},
item: {
singular: `item`,
singularCamelCase: `Item`,
plural: `items`,
pluralCamelCase: `Items`
},
shortcut: {
singular: `shortcut`,
singularCamelCase: `Shortcut`,
plural: `shortcuts`,
pluralCamelCase: `Shortcuts`
}
};
const DO_ACTIONS_TEMPLATE = (action, dataTypes) => `${action}: {
${dataTypes}
}`;
const DATA_TYPES_TEMPLATE = (
type,
singularTemplate,
pluralTemplate
) => `${type}: (count: number) => plural(count, {
one: \`${singularTemplate}\`,
other: \`${pluralTemplate}\`
})`;
const MODULE_TEMPLATE = (exportName, strings) =>
`/* eslint-disable header/header */
// THIS FILE IS GENERATED. DO NOT EDIT MANUALLY.
import { t, plural } from "@lingui/macro";
export const ${exportName} = {
${strings}
};
`;
function generateDoActionsStrings() {
return generateStrings(
DO_ACTIONS,
(action, type) => `${action} ${DATA_TYPES[type].singular}`,
(action, type) => `${action} # ${DATA_TYPES[type].plural}`
);
}
function generateActionsStrings() {
return generateStrings(
ACTIONS,
(action, type) => `${DATA_TYPES[type].singularCamelCase} ${action}`,
(action, type) => `# ${DATA_TYPES[type].plural} ${action}`
);
}
function generateActionConfirmationStrings() {
return generateStrings(
ACTION_CONFIRMATIONS,
(action, type) =>
`Are you sure you want to ${action} this ${DATA_TYPES[type].singular}?`,
(action, type) =>
`Are you sure you to ${action} these ${DATA_TYPES[type].plural}?`
);
}
function generateActionErrorStrings() {
return generateStrings(
ACTION_ERRORS,
(action, type) =>
`${DATA_TYPES[type].singularCamelCase} could not be ${action}`,
(action, type) => `# ${DATA_TYPES[type].plural} could not be ${action}`
);
}
function generateInProgressActionsStrings() {
return generateStrings(
IN_PROGRESS_ACTIONS,
(action, type) => `${action} ${DATA_TYPES[type].singular}...`,
(action, type) => `${action} # ${DATA_TYPES[type].plural}...`
);
}
function generateStrings(actions, singular, plural) {
let result = [];
for (const action of actions) {
const subResults = [];
for (const type of action.dataTypes) {
const actionName = action.label;
subResults.push(
DATA_TYPES_TEMPLATE(
type,
singular(actionName, type),
plural(actionName, type)
)
);
}
result.push(DO_ACTIONS_TEMPLATE(action.action, subResults.join(",\n")));
}
return result.join(",\n");
}
mkdirSync("./generated/", { recursive: true });
writeFileSync(
"./generated/do-actions.ts",
MODULE_TEMPLATE("doActions", generateDoActionsStrings())
);
writeFileSync(
"./generated/actions.ts",
MODULE_TEMPLATE("actions", generateActionsStrings())
);
writeFileSync(
"./generated/in-progress-actions.ts",
MODULE_TEMPLATE("inProgressActions", generateInProgressActionsStrings())
);
writeFileSync(
"./generated/action-errors.ts",
MODULE_TEMPLATE("actionErrors", generateActionErrorStrings())
);
writeFileSync(
"./generated/action-confirmations.ts",
MODULE_TEMPLATE("actionConfirmations", generateActionConfirmationStrings())
);

View File

@@ -17,44 +17,27 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { plural, select, t } from "@lingui/macro";
import { fail } from "assert";
import { doActions } from "../generated/do-actions";
import { actions } from "../generated/actions";
import { inProgressActions } from "../generated/in-progress-actions";
import { actionErrors } from "../generated/action-errors";
import { actionConfirmations } from "../generated/action-confirmations";
const actions = {
deleted: () => t`deleted`,
unpinned: () => t`unpinned`,
pinned: () => t`pinned`,
unpublished: () => t`unpublished`,
published: () => t`published`,
permanentlyDeleted: () => t`permanently deleted`,
restored: () => t`restored`,
edited: () => t`edited`,
created: () => t`created`,
renamed: () => t`renamed`
const SEARCH_IN_ROUTE_STRINGS = {
Notes: () => t`Type a keyword to search in Notes`,
Notebooks: () => t`Type a keyword to search in Notebooks`,
Notebook: () => t`Type a keyword to search in Notebook`,
Favorites: () => t`Type a keyword to search in Favorites`,
Reminders: () => t`Type a keyword to search in Reminders`,
Trash: () => t`Type a keyword to search in Trash`,
Settings: () => t`Type a keyword to search in Settings`,
Tags: () => t`Type a keyword to search in Tags`,
Editor: () => t`Type a keyword to search in Editor`,
Home: () => t`Type a keyword to search in Home`,
Search: () => t`Type a keyword to search in Search`,
Monographs: () => t`Type a keyword to search in Monographs`
};
const doActions = {
delete: () => t`Delete`,
unpin: () => t`Unpin`,
pin: () => t`Pin`,
unpublish: () => t`Unpublish`,
publish: () => t`Publish`,
permanentlyDelete: () => t`Permanently delete`,
restore: () => t`Restore`,
edit: () => t`Edit`,
create: () => t`Created`,
rename: () => t`Rename`,
remove: () => t`Remove`,
download: () => t`Download`
};
const inProgressActions = {
deleting: () => t`Delete`
};
type Actions = keyof typeof actions;
type DoActions = keyof typeof doActions;
type InProgressActions = keyof typeof inProgressActions;
export const strings = {
done: () => t`Done`,
verifyItsYou: () => t`Please verify it's you`,
@@ -67,10 +50,11 @@ export const strings = {
}),
downloading: () => t`Downloading`,
uploading: () => t`Uploading`,
networkProgress: (type: "upload" | "download") =>
networkProgress: (type: "upload" | "download" | "sync") =>
select(type, {
upload: "Uploading",
download: "Downloading",
sync: "Syncing",
other: "Loading"
}),
tapToCancel: () => t`Tap to cancel`,
@@ -326,10 +310,14 @@ export const strings = {
item: () => t`Items`,
shortcut: () => t`Shortcuts`
},
addItem: (referenceType: string) =>
t`Add a ${strings.dataTypes[
referenceType as keyof typeof strings.dataTypes
]()}`,
addItem: (itemType: "tag" | "notebook" | "reminder" | "note") =>
select(itemType, {
tag: `Add a tag`,
notebook: `Add a notebook`,
reminder: `Add a reminder`,
note: `Add a note`,
other: `Add an item`
}),
reminderRepeatStrings: {
day: (date: string) => t`Repeats daily at ${date}`,
week: {
@@ -340,21 +328,32 @@ export const strings = {
month: {
selectDays: () => t`Select nth day of the month to repeat the reminder.`
},
repeats: (freq: number, mode: string, selectedDays: string, date: string) =>
plural(freq, {
one: `Repeats every ${strings.reminderRepeatMode[
mode as keyof typeof strings.reminderRepeatMode
]()} on ${selectedDays} at ${date}`,
other: `Repeats every ${freq} ${strings.reminderRepeatMode[
mode as keyof typeof strings.reminderRepeatMode
]()} every ${selectedDays} at ${date}`
})
},
reminderRepeatMode: {
day: () => t`day`,
week: () => t`week`,
month: () => t`month`,
year: () => t`year`
repeats: (
freq: number,
mode: string,
selectedDays: string,
date: string
) => {
const strings = {
day: plural(freq, {
one: `Repeats every day on ${selectedDays} at ${date}`,
other: `Repeats every # day every ${selectedDays} at ${date}`
}),
week: plural(freq, {
one: `Repeats every week on ${selectedDays} at ${date}`,
other: `Repeats every # week every ${selectedDays} at ${date}`
}),
month: plural(freq, {
one: `Repeats every month on ${selectedDays} at ${date}`,
other: `Repeats every # month every ${selectedDays} at ${date}`
}),
year: plural(freq, {
one: `Repeats every year on ${selectedDays} at ${date}`,
other: `Repeats every # year every ${selectedDays} at ${date}`
})
};
return strings[mode as keyof typeof strings];
}
},
remindMeIn: () => t`Remind me in`,
referencedIn: () => t`REFERENCED IN`,
@@ -362,13 +361,13 @@ export const strings = {
t`Select the folder that includes your backup files to list them here.`,
noBackupsFound: () => t`No backups found`,
restoring: () => t`Restoring`,
restoringCollection: (collection: string) => t`Restoring ${collection}...`,
checkNewVersion: () => t`Checking for new version`,
noUpdates: () => t`No updates available`,
updateAvailable: () => t`Update available`,
versionReleased: (version: string, type: "github" | "store") =>
select(type, {
github: `v${version} has been released on GitHub`,
store: `v${version} has been released`,
other: `v${version} has been released`
}),
readReleaseNotes: () => t`Read full release notes on Github`,
@@ -387,7 +386,7 @@ export const strings = {
gettingRecoveryCodes: () => t`Getting recovery codes`,
protectNotes: () => t`Protect your notes`,
protectNotesDesc: () => t`Choose how you want to secure your notes locally.`,
loggingOut: () => t`Logging out`,
loggingOut: () => t`Logging out. Please wait...`,
loggingOutDesc: () => t`Please wait while we log you out.`,
by: () => t`By`,
noResultsForSearch: (query: string) => t`No results found for "${query}"`,
@@ -431,7 +430,7 @@ $headline$: Use starting line of the note as title.`,
vaultFingerprintUnlock: () => t`Vault Fingerprint Unlock`,
revokeVaultFingerprintUnlock: () => t`Revoke Vault Fingerprint Unlock`,
changeVaultPassword: () => t`Change Vault Password`,
deleteNote: () => t`Delete note`,
deleteNote: () => doActions.delete.note(1),
shareNote: () => t`Share note`,
copyNote: () => t`Copy note`,
goToEditor: () => t`Unlock note`,
@@ -448,6 +447,8 @@ $headline$: Use starting line of the note as title.`,
t`Your account email will be changed without affecting your subscription or any other settings.`,
changeEmailNotice: () => t`You will be logged out from all your devices`,
export: () => t`Export`,
exportNotes: (notes: number) =>
plural(notes, { one: "Export note", other: "Export # notes" }),
issueTitle: () => t`Report issue`,
issueDesc: () =>
t`We are sorry, it seems that the app crashed due to an error. You can submit a bug report below so we can fix this asap.`,
@@ -463,7 +464,8 @@ $headline$: Use starting line of the note as title.`,
}),
addNotesToNotebook: (title: string) => t`Add notes to ${title}`,
publish: () => t`Publish`,
publishDesc: () =>
publishNote: () => t`Publish note`,
publishNoteDesc: () =>
t`Publish your note to share it with others. You can set a password to protect it.`,
saveRecoveryKey: () => t`Save account recovery key`,
saveRecoveryKeyDesc: () =>
@@ -481,7 +483,8 @@ $headline$: Use starting line of the note as title.`,
twoFactorAuthEnabled: () => t`Two-factor authentication enabled`,
listOf: () => t`List of`,
network: {
downloading: () => t`Downloading`,
downloading: (progress?: string | number) =>
progress ? t`Downloading (${progress})` : t`Downloading`,
downloaded: () => t`Downloaded`,
download: () => t`Download`,
upload: () => t`Upload`,
@@ -498,7 +501,7 @@ $headline$: Use starting line of the note as title.`,
redo: () => t`Redo`,
createYourAccount: () => t`Create your account`,
pinned: () => t`Pinned`,
editNotebook: () => t`Edit notebook`,
editNotebook: () => doActions.edit.notebook(1),
newNotebook: () => t`New notebook`,
newInternalLink: () => t`Link to note`,
editInternalLink: () => t`Edit internal link`,
@@ -506,7 +509,9 @@ $headline$: Use starting line of the note as title.`,
tabs: () => t`Tabs`,
add: () => t`Add`,
newVersion: () => t`New version`,
editReminder: () => t`Edit reminder`,
newVersionHighlights: (version?: string) =>
t`${version ? `v${version} ` : "New version"} Highlights 🎉`,
editReminder: () => doActions.edit.reminder(1),
newReminder: () => t`New reminder`,
sortBy: () => t`Sort by`,
groupBy: () => t`Group by`,
@@ -542,7 +547,6 @@ $headline$: Use starting line of the note as title.`,
keep: () => t`Keep`,
restore: () => t`Restore`,
deletePermanently: () => t`Delete permanently`,
deletedPermanently: () => t`deleted permanently`,
viewAllLinkedNotebooks: () => t`View all linked notebooks`,
learnMore: () => t`Learn more`,
addTag: () => t`Add tag`,
@@ -635,7 +639,7 @@ $headline$: Use starting line of the note as title.`,
},
downloadUpdate: () => t`Download update`,
stopReordering: () => t`Tap to stop reordering`,
removeShortcut: () => t`Remove shortcut`,
removeShortcut: () => doActions.remove.shortcut(1),
createShortcut: () => t`Create a shortcut`,
tip: () => t`TIP`,
neverShowAgain: () => t`Never show again`,
@@ -749,7 +753,10 @@ $headline$: Use starting line of the note as title.`,
enterPassword: () => t`Enter password`,
failedToDownloadFile: () => t`Failed to download file`,
zipping: () => t`Zipping`,
savingZipFile: () => t`Saving zip file`,
savingZipFile: (progress?: string) =>
progress
? t`Saving zip file (${progress}%). Please wait...`
: t`Saving zip file. Please wait...`,
failedToZipFiles: () => t`Failed to zip files`,
fileVerificationFailed: () => t`Uploaded file verification failed.`,
fileLengthError: () =>
@@ -793,34 +800,15 @@ $headline$: Use starting line of the note as title.`,
user: "@andrewsayer on Twitter"
}
],
shortcutCreated: () => t`Shortcut created`,
notebookRestored: () => t`Notebook restored`,
restoreNotebook: () => t`Restore notebook`,
permanentlyDeletedNotebook: () => t`Permanently deleted notebook`,
shortcutCreated: () => actions.created.shortcut(1),
notebookRestored: () => actions.restored.notebook(1),
restoreNotebook: () => doActions.restore.notebook(1),
permanentlyDeletedNotebook: () => actions.permanentlyDeleted.notebook(1),
noteRestoredFromHistory: () => t`Note restored from history`,
noteRestored: () => t`Note restored`,
deleteNoteConfirmation: () =>
t`Are you sure you want to delete this note permanently?`,
noteDeleted: () => t`Note deleted`,
noteRestored: () => actions.restored.note(1),
deleteNoteConfirmation: () => actionConfirmations.permanentlyDelete.note(1),
noteDeleted: () => actions.deleted.note(1),
restored: () => t`Restored successfully`,
deleteItems: (type: string, count: number) =>
plural(count, {
one: `Delete ${strings.dataTypes[
type as keyof typeof strings.dataTypes
]()}`,
other: `Delete ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypes
]()}`
}),
deleteItemsConfirmation: (type: string, count: number) =>
plural(count, {
one: `Are you sure you want to delete this ${strings.dataTypes[
type as keyof typeof strings.dataTypes
]()} permanently?`,
other: `Are you sure you want to delete these ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypes
]()} permanently?`
}),
manageTags: () => t`Manage tags`,
linkNotebook: () => t`Link to notebook`,
move: () => t`Move`,
@@ -840,7 +828,7 @@ $headline$: Use starting line of the note as title.`,
}),
failedToPublish: () => t`Failed to publish note`,
failedToUnpublish: () => t`Failed to unpublish note`,
notePublished: () => t`Note published`,
notePublished: () => actions.published.note(1),
monographUrlCopied: () => t`Monograph URL copied`,
recoveryKeySaved: () => t`Did you save recovery key?`,
recoveryKeySavedDesc: () =>
@@ -855,22 +843,13 @@ $headline$: Use starting line of the note as title.`,
},
backupEncrypted: () => t`Backup is encrypted`,
password: () => t`Password`,
renameTag: () => t`Rename tag`,
renameColor: () => t`Rename color`,
renameTag: () => doActions.rename.tag(1),
renameColor: () => doActions.rename.color(1),
renameColorDesc: (color: string) => t`You are renaming color ${color}`,
name: () => t`Name`,
unlockToDelete: () => t`Unlock note to delete it`,
backupRestored: () => t`Backup restored`,
restoreFailed: () => t`Restore failed`,
itemDeleted: (count: number, type: string) =>
plural(count, {
one: `1 ${strings.dataTypesCamelCase[
type as keyof typeof strings.dataTypesCamelCase
]()} deleted`,
other: `# ${strings.dataTypes[
type as keyof typeof strings.dataTypes
]()} deleted`
}),
reorder: () => t`Reorder`,
turnOffReminder: () => t`Turn off reminder`,
turnOnReminder: () => t`Turn on reminder`,
@@ -894,12 +873,15 @@ $headline$: Use starting line of the note as title.`,
readOnly: () => t`Read only`,
syncOff: () => t`Sync off`,
syncOffConfirm: (count: number) =>
t`Prevent ${strings.itemsPlural("note", count)} from syncing`,
plural(count, {
one: `Prevent note from syncing`,
other: `Prevent # notes from syncing`
}),
syncOffDesc: (count: number) =>
`${strings.itemsPlural(
"note",
count
)} will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?`,
plural(count, {
one: `Note will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?`,
other: `# notes will be automatically deleted from all other devices & any future changes won't get synced. Are you sure you want to continue?`
}),
duplicate: () => t`Duplicate`,
remindMe: () => t`Remind me`,
published: () => t`Published`,
@@ -908,7 +890,7 @@ $headline$: Use starting line of the note as title.`,
linkNotebooks: () => t`Link notebooks`,
unlinkFromAll: () => t`Unlink from all`,
removeFromAll: () => t`Remove from all`,
assignTo: () => t`Assign to`,
assignTo: () => t`Assign to...`,
addTags: () => t`Add tags`,
addTagsDesc: () => t`Add tags to multiple notes at once`,
references: () => t`References`,
@@ -1310,18 +1292,17 @@ NOTE: Creating a backup with attachments can take a while, and also fail complet
backupDataDesc: () =>
t`All your backups are stored in 'Phone Storage/Notesnook/backups/' folder`,
backupSuccess: () => t`Backup successful`,
biometricsAuthFailed: () => t`Biometrics authentication failed`,
biometricsAuthFailed: () =>
t`Biometrics authentication failed. Please try again.`,
biometricsAuthFailedDesc: () => t`Wait 30 seconds to try again`,
biometricsAuthCancelled: () => t`Authentication cancelled by user`,
biometricsAuthError: () => t`Authentication failed`,
tryAgain: () => t`Tap to try again`,
rateAppMessage: () => t`We would love to know what you think!`,
rateAppActionText: (platform: string) =>
t`Rate Notesnook on ${
platform === "ios" ? strings.appStore() : strings.playStore()
}`,
appStore: () => t`App Store`,
playStore: () => t`Play Store`,
platform === "ios"
? t`Rate Notesnook on App Store`
: t`Rate Notesnook on Play Store`,
recoveryKeyMessage: () => t`Keep your data safe`,
recoveryKeyMessageActionText: () => t`Save your account recovery key`,
loginMessage: () => t`You are not logged in`,
@@ -1441,20 +1422,6 @@ NOTE: Creating a backup with attachments can take a while, and also fail complet
],
someNotesPublished: () => t`Some notes are published`,
unpublishToDelete: () => t`Unpublish notes to delete them`,
deleteTags: (count: number) =>
plural(count, {
one: "Delete tag",
other: "Delete # tags"
}),
deleteTagsConfirm: () => t`Are you sure you want to delete these tags?`,
deleteItemConfirmation: (itemType: string) =>
t`Are you sure you want to delete this ${strings.dataTypes[
itemType as keyof typeof strings.dataTypes
]()}?`,
deleteItem: (itemType: string) =>
t`Delete ${strings.dataTypes[
itemType as keyof typeof strings.dataTypes
]()}`,
filterAttachments: () => t`Filter attachments by filename, type or hash`,
oldPassword: () => t`Old password`,
newPassword: () => t`New password`,
@@ -1485,11 +1452,7 @@ For example:
searchANote: () => t`Search a note`,
remindeMeOf: () => t`Remind me of...`,
addShortNote: () => t`Add a short note`,
typeAKeywordToSearchIn: (route: string) =>
t`Type a keyword to search in ${strings.routes[
route as keyof typeof strings.routes
]()}...`,
searchingFor: (query: string) => t`Searching for ${query}`,
searchingFor: (query: string) => t`Searching for ${query}...`,
typeAKeyword: () => t`Type a keyword`,
search: () => t`Search`,
enterEmailAddress: () => t`Enter email address`,
@@ -1511,10 +1474,9 @@ For example:
Search: () => t`Search`,
Monographs: () => t`Monographs`
},
searchInRoute: (routeName: string) =>
t`Type a keyword to search in ${
strings.routes[routeName as keyof typeof strings.routes]?.() || routeName
}`,
searchInRoute: (routeName: keyof typeof SEARCH_IN_ROUTE_STRINGS) => {
return SEARCH_IN_ROUTE_STRINGS[routeName]();
},
logoutConfirmation: () =>
t`Are you sure you want to logout and clear all data stored on THIS DEVICE?`,
backupDataBeforeLogout: () => t`Take a backup before logging out`,
@@ -1533,11 +1495,15 @@ For example:
t`Please grant notifications permission to add new reminders.`,
selectDayError: () => t`Please select the day to repeat the reminder on`,
setTitleError: () => t`Please set title of the reminder`,
dateError: () => t`Reminder date must be set in future`,
dateError: () => t`Reminder time cannot be earlier than the current time.`,
failedToDecryptBackup: () => t`Failed to decrypt backup`,
backupDirectoryNotSelected: () => t`Backup directory not selected`,
legal: () => t`legal`,
days: () => t`days`,
days: (days: number) =>
plural(days, {
one: `1 day`,
other: `# days`
}),
daily: () => t`Daily`,
weekly: () => t`Weekly`,
monthly: () => t`Monthly`,
@@ -1568,7 +1534,8 @@ For example:
noteLockedBlockLink: () =>
t`Linking to a specific block is not available for locked notes.`,
dismiss: () => t`Dismiss`,
words: () => t`words`,
totalWords: (words: number) =>
plural(words, { one: "# word", other: "# words" }),
addATag: () => t`Add a tag`,
startWritingNote: () => t`Start writing your note...`,
off: () => t`Off`,
@@ -1582,7 +1549,7 @@ For example:
restoreFromFiles: () => t`Restore from files`,
recentBackups: () => t`RECENT BACKUPS`,
restoringBackup: () => t`Restoring backup...`,
restoringBackupDesc: () => t`Please wait while we restore your backup`,
restoringBackupDesc: () => t`Please wait while we restore your backup...`,
decryptingBackup: () => t`Backup is encrypted, decrypting...`,
preparingBackupRestore: () => t`Preparing to restore backup file...`,
readingBackupFile: () => t`Reading backup file...`,
@@ -1608,9 +1575,9 @@ For example:
connectedToServer: () => t`Connected to all servers sucessfully.`,
allServerUrlsRequired: () => t`All server urls are required.`,
serverNotFound: (host: string) => t`Server with host ${host} not found.`,
couldNotConnectTo: (server: string) => t`Could not connect to ${server}`,
couldNotConnectTo: (server: string) => t`Could not connect to ${server}.`,
incorrectServerUrl: (url: string, server: string) =>
t`The URL you have given (${url}) does not point to the ${server}`,
t`The URL you have given (${url}) does not point to the ${server}.`,
serverVersionMismatch: (title: string, url: string) =>
t`The ${title} at ${url} is not compatible with this client.`,
testConnectionBeforeSave: () =>
@@ -1631,9 +1598,9 @@ For example:
],
restoreThisVersion: () => t`Restore this version`,
autoSaveOff: () => t`Auto save: off`,
selected: () => t`selected`,
selectedWords: (words: number) => plural(words, { other: "# selected" }),
dropFilesToAttach: () => t`Drop your files here to attach`,
loadingEditor: () => t`Loading editor`,
loadingEditor: () => t`Loading editor. Please wait...`,
noHeadingsFound: () => t`No headings found`,
somethingWentWrong: () => t`Something went wrong`,
whatWentWrong: () => t`What went wrong?`,
@@ -1671,22 +1638,14 @@ For example:
zoomOut: () => t`Zoom out`,
zoomIn: () => t`Zoom in`,
enterFullScreen: () => t`Enter fullscreen`,
syncingYour: (context: string) =>
t`Syncing your ${strings.routes[
(context.slice(0, 1).toUpperCase() +
context.slice(1)) as keyof typeof strings.routes
]()}`,
syncingYourNotes: () => t`Syncing your notes`,
items: () => t`items`,
downloadingImages: () => t`Downloading images`,
checkingForUpdates: () => t`Checking for updates`,
updating: () => t`updating`,
restartRequired: () => t`restart required`,
available: () => t`available`,
itemsRestored: (count: number) =>
plural(count, {
one: `# item restored`,
other: `# items restored`
}),
updating: (percentage: number) => t`${percentage}% updating...`,
updateCompleted: (version: string) =>
`v${version} downloaded (click to install)`,
updateNewVersionAvailable: (version: string) => t`v${version} available`,
unlocking: () => t`Unlocking`,
reminderStarts: (date: string, time: string) =>
t`The reminder will start on ${date} at ${time}.`,
@@ -1801,6 +1760,7 @@ For example:
dontShowAgainConfirm: () => t`Don't show again on this device?`,
toggleDarkLightMode: () => t`Toggle dark/light mode`,
goTo: () => t`Go to`,
goToTag: (tag: string) => t`Go to #${tag}`,
tagNotFound: () => `Tag not found`,
downloadAllAttachments: () => t`Download all attachments`,
selectProfilePicture: () => t`Select profile picture`,
@@ -1855,7 +1815,8 @@ For example:
properties: () => t`Properties`,
clickToPreview: () => t`Click to preview`,
clearCache: () => t`Clear cache`,
clearCacheDesc: () => t`Clear all cached attachments`,
clearCacheDesc: (cacheSize: number) =>
t`Clear all cached attachments. Current cache size: ${cacheSize}`,
clearCacheConfirm: () => t`Clear attachments cache?`,
clearCacheConfirmDesc:
() => t`Clearing attachments cache will perform the following actions:
@@ -1898,94 +1859,22 @@ All attachments will be downloaded & cached again on access.
backingUpDataWait: () =>
t`We are creating a backup of your data. Please wait...`,
resetAccountPassword: () => t`Reset account password`,
resettingAccountPassword: () => t`Resetting account password`,
resettingAccountPassword: (progress: number) =>
t`Resetting account password (${progress})`,
resetPasswordWait: () => t`Please wait while we reset your account password.`,
recoverySuccess: () => t`Recovery successful!`,
recoverySuccessDesc: () => t`Your account has been recovered.`,
upgradeNow: () => t`Upgrade now`,
backupSavedAt: (path: string) => t`Backup saved at ${path}`,
movedToTrash: (type: string, count: number) =>
plural(count, {
one: `1 ${strings.dataTypes[
type as keyof typeof strings.dataTypes
]()} moved to trash`,
other: `# ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()} moved to trash`
}),
irreverisibleAction: () => t`This action is IRREVERSIBLE.`,
doAction: (type: string, count: number, action: DoActions) =>
plural(count, {
one: `${doActions[action]()} ${strings.dataTypesCamelCase[
type as keyof typeof strings.dataTypes
]()}?`,
other: `${doActions[action]()} # ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()}?`
}),
action: (type: string, count: number, action: Actions) =>
plural(count, {
one: `${strings.dataTypesCamelCase[
type as keyof typeof strings.dataTypes
]()} ${actions[action]()}`,
other: `# ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()} ${actions[action]()}`
}),
inProgressAction: (type: string, count: number, action: InProgressActions) =>
plural(count, {
one: `${inProgressActions[action]()} ${strings.dataTypesCamelCase[
type as keyof typeof strings.dataTypes
]()}`,
other: `${inProgressActions[action]()} # ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()}`
}),
actionError: (type: string, count: number, action: Actions) =>
plural(count, {
one: `${strings.dataTypesCamelCase[
type as keyof typeof strings.dataTypes
]()} could not be ${actions[action]}`,
other: `# ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()} could not be ${actions[action]}`
}),
deleted: (type: string, count: number) =>
plural(count, {
one: `${strings.dataTypesCamelCase[
type as keyof typeof strings.dataTypes
]()} deleted`,
other: `# ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()} deleted`
}),
unpinned: (type: string, count: number) =>
plural(count, {
one: `${strings.dataTypesCamelCase[
type as keyof typeof strings.dataTypes
]()} unpinned`,
other: `# ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()} unpinned`
}),
deleting: () => t`Deleting`,
deletingItems: (type: string, count: number) =>
plural(count, {
one: `Deleting ${strings.dataTypes[
type as keyof typeof strings.dataTypes
]()}`,
other: `Deleting ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()}`
}),
itemsPlural: (type: string, count: number) =>
plural(count, {
one: `${strings.dataTypes[type as keyof typeof strings.dataTypes]()}`,
other: `# ${strings.dataTypesPlural[
type as keyof typeof strings.dataTypesPlural
]()}`
}),
doActions,
actions,
inProgressActions,
actionErrors,
actionConfirmations,
deleting: () => t`Deleting`,
backupReadyToDownload: () => t`Your backup is ready to download`,
vaultUnlocked: () => t`Vault unlocked`,
vaultLocked: () => t`Vault locked`,
@@ -2008,23 +1897,42 @@ All attachments will be downloaded & cached again on access.
},
noteDoesNotExist: () => t`Note does not exist`,
couldNotConvertNote: (format: string) =>
t`Could not convert note to ${format}`,
t`Could not convert note to ${format}.`,
remindersNotSupported: () =>
t`Reminders will not be active on this device as it does not support notifications.`,
invalidHexColor: () => t`Please enter a valid hex color (e.g. #ffffff)`,
profileUpdated: () => t`Profile updated`,
addedToNotebook: (count: number) =>
plural(count, {
one: `added to 1 notebook`,
other: `added to # notebooks`
}),
removedFromNotebook: (count: number) =>
plural(count, {
one: `removed from 1 notebook`,
other: `removed from # notebooks`
}),
assignedToNotebookMessage: (
notes: number,
added: number,
removed: number
) => {
const n = plural(notes, {
one: `1 note`,
other: `# notes`
});
if (added === 0 && removed > 0)
return t`${n} ${plural(removed, {
one: `removed from 1 notebook`,
other: `removed from # notebooks`
})}.`;
else if (added > 0 && removed === 0)
return t`${n} ${plural(added, {
one: `added to 1 notebook`,
other: `added to # notebooks`
})}.`;
else
return t`${n} ${plural(added, {
one: `added to 1 notebook`,
other: `added to # notebooks`
})} and ${plural(removed, {
one: `removed from 1 notebook`,
other: `removed from # notebooks`
})}.`;
},
noEncryptionKeyFound: () => t`No encryption key found`,
couldNotActivateTrial: () => t`Could not activate trial`,
couldNotActivateTrial: () =>
t`Could not activate trial. Please try again later.`,
pleaseTryAgain: () => t`Please try again`,
securityKeyRegistered: () => t`Security key successfully registered.`,
restartNow: () => t`Restart now`,
@@ -2036,13 +1944,13 @@ All attachments will be downloaded & cached again on access.
subCanceled: () => t`Your subscription has been canceled.`,
refundIssued: () =>
t`Your refund has been issued. Please wait 24 hours before reaching out to us in case you do not receive your funds.`,
failedToInstallTheme: () => t`Failed to install theme`,
failedToInstallTheme: () => t`Failed to install theme.`,
fullNameUpdated: () => t`Full name updated`,
shortcutRemoved: () => t`Shortcut removed`,
recheckFailed: () => t`Rechecking failed`,
failedToDelete: () => t`Failed to delete`,
failedToRegisterTask: () => t`Failed to register task`,
couldNotClearTrash: () => t`Could not clear trash`,
couldNotClearTrash: () => t`Could not clear trash.`,
automaticBackupsDisabled: () => t`Automatic backups disabled`,
automaticBackupsDisabledDesc: () =>
t`Please upgrade to Pro to enable automatic backups.`,
@@ -2069,7 +1977,7 @@ All attachments will be downloaded & cached again on access.
rotateRight: () => t`Rotate right`,
website: () => t`Website`,
resetSidebar: () => t`Reset sidebar`,
removeColor: () => t`Remove color`,
removeColor: () => doActions.remove.color(1),
favorite: () => t`Favorite`,
assignColor: () => t`Assign color`,
print: () => t`Print`,
@@ -2084,7 +1992,8 @@ All attachments will be downloaded & cached again on access.
editingTagDesc: (tag: string) => t`You are editing #${tag}`,
applyingChanges: () => t`Applying changes`,
thisMayTakeAWhile: () => t`This may take a while`,
processing: () => t`Processing`,
processing: () => t`Processing...`,
processingCollection: (collection: string) => t`Processing ${collection}...`,
root: () => t`Root`,
credientials: () => t`Credentials`,
thankYouForReporting: () => t`Thank you for reporting!`,
@@ -2440,7 +2349,6 @@ Use this if changes from other devices are not appearing on this device. This wi
passed: () => t`Passed`,
failed: () => t`Failed`,
cacheClearedDesc: () => t`All cached attachments have been cleared.`,
currentCacheSize: (size: string) => t`Current cache size: ${size}`,
restoreBackupConfirm: () => t`Restore backup?`,
serversConfigurationDesc: () => t`Configure server URLs for Notesnook`,
prioritySupport: () => t`Get Priority support`,
@@ -2460,5 +2368,6 @@ Use this if changes from other devices are not appearing on this device. This wi
schoolWork: () => t`School work`,
schoolWorkDesc: () => t`Everything related to my school in one place.`,
recipes: () => t`Recipes`,
recipesDesc: () => t`I love cooking and collecting recipes.`
recipesDesc: () => t`I love cooking and collecting recipes.`,
error: () => t`Error`
};

View File

@@ -32,13 +32,17 @@ export default defineConfig({
syntax: "typescript",
tsx: true
},
baseUrl: "./",
paths: {
"$src/*": ["src/*"]
},
experimental: {
plugins: [
[
"@lingui/swc-plugin",
{
runtimeModules: {
i18n: ["./setup", "i18n"]
i18n: ["$src/setup", "i18n"]
}
}
]