mobile: fix localization

This commit is contained in:
Ammar Ahmed
2024-11-07 12:23:21 +05:00
parent 21ada0e2d2
commit faae68928b
13 changed files with 210 additions and 176 deletions

View File

@@ -235,7 +235,7 @@ export const AttachmentDialog = ({
for (let i = 0; i < filteredAttachments.placeholders.length; i++) {
if (!getState().isWorking) {
ToastManager.show({
message: "Attachment recheck cancelled",
message: strings.attachmentRecheckCancelled(),
type: "info",
context: isSheet ? "local" : "global"
});
@@ -322,7 +322,7 @@ export const AttachmentDialog = ({
) : null}
{!isSheet ? (
<Header
title="Manage attachments"
title={strings.manageAttachments()}
renderedInRoute="SettingsGroup"
canGoBack
headerRightButtons={[
@@ -330,23 +330,25 @@ export const AttachmentDialog = ({
onPress() {
onCheck();
},
title: "Recheck all"
title: strings.recheckAll()
},
{
onPress() {
if (!attachments) return;
presentDialog({
title: `Download ${attachments.placeholders.length} attachments`,
paragraph:
"Are you sure you want to download all attachments?",
positiveText: "Download",
title: strings.doAction(
"attachment",
attachments.placeholders.length,
"download"
),
positiveText: strings.network.download(),
positivePress: async () => {
downloadAttachments(await attachments.ids());
},
negativeText: "Cancel"
negativeText: strings.cancel()
});
},
title: "Download all"
title: strings.downloadAllAttachments()
}
]}
/>
@@ -388,15 +390,16 @@ export const AttachmentDialog = ({
onPress={() => {
if (!attachments) return;
presentDialog({
title: `Download ${attachments.placeholders.length} attachments`,
paragraph:
"Are you sure you want to download all attachments?",
context: "local",
positiveText: "Download",
title: strings.doAction(
"attachment",
attachments.placeholders.length,
"download"
),
positiveText: strings.network.download(),
positivePress: async () => {
downloadAttachments(await attachments.ids());
},
negativeText: "Cancel"
negativeText: strings.cancel()
});
}}
size={SIZE.lg}
@@ -457,14 +460,16 @@ export const AttachmentDialog = ({
<Paragraph>
{rechecker.isWorking
? note
? `Checking ${rechecker.filter.toLowerCase()} note attachments`
: `Checking ${rechecker.filter.toLowerCase()} attachments`
: "Attachments recheck complete"}
? strings.checkingNoteAttachments()
: strings.checkingAllAttachments()
: strings.attachmentRecheckComplete()}
</Paragraph>
<Paragraph>
{`${rechecker.isWorking ? "Please wait... " : ""}Passed: ${
{`${
rechecker.isWorking ? `${strings.pleaseWait()} ` : ""
}${strings.passed()}: ${
rechecker.passed
}, Failed: ${rechecker.failed}`}
}, ${strings.failed()}: ${rechecker.failed}`}
</Paragraph>
</View>
</View>

View File

@@ -17,6 +17,9 @@ 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 { Notebook } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import { Linking, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
@@ -26,26 +29,22 @@ import {
SUPPORT_SVG,
WELCOME_SVG
} from "../../assets/images/assets";
import { ThemeStore } from "../../stores/use-theme-store";
import useRotator from "../../hooks/use-rotator";
import { eSendEvent } from "../../services/event-manager";
import { getContainerBorder } from "../../utils/colors";
import { getElevationStyle } from "../../utils/elevation";
import { eOpenAddNotebookDialog } from "../../utils/events";
import { SIZE } from "../../utils/size";
import useRotator from "../../hooks/use-rotator";
import { AccentColorPicker } from "../../screens/settings/appearance";
import { Button } from "../ui/button";
import { SvgView } from "../ui/svg";
import { PinItem } from "../side-menu/pinned-section";
import { Button } from "../ui/button";
import Seperator from "../ui/seperator";
import { SvgView } from "../ui/svg";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { useThemeColors } from "@notesnook/theme";
import { getContainerBorder } from "../../utils/colors";
import { strings } from "@notesnook/intl";
export type TStep = {
text?: string;
walkthroughItem: (colors: ThemeStore["colors"]) => React.ReactNode;
walkthroughItem: (colors: any) => React.ReactNode;
title?: string;
button?: {
type: "next" | "done";
@@ -62,18 +61,18 @@ const NotebookWelcome = () => {
const { colors } = useThemeColors();
const data = useRotator([
{
title: "Work and office",
description: "Everything related to my job",
title: strings.workAndOffice(),
description: strings.workAndOfficeDesc(),
count: 2
},
{
title: "School work",
description: "I don't like doing this but I have to.",
title: strings.schoolWork(),
description: strings.schoolWorkDesc(),
count: 5
},
{
title: "Recipes",
description: "I love cooking and collecting recipes",
title: strings.recipes(),
description: strings.recipesDesc(),
count: 10
}
]);
@@ -122,17 +121,17 @@ const notebooks: { id: string; steps: TStep[] } = {
id: "notebooks",
steps: [
{
title: "Notebooks",
text: "Boost your productivity with Notebooks and organize your notes.",
title: strings.notebooks(),
text: strings.boostProductivityNotebook(),
walkthroughItem: () => <NotebookWelcome />,
button: {
type: "next",
title: "Next"
title: strings.next()
}
},
{
title: "Notebook > Notes",
text: "Every Notebook can have notes and sub notebooks.",
title: strings.notebookNotes(),
text: strings.notebookNotesDesc(),
walkthroughItem: (colors: any) => (
<View
style={{
@@ -154,9 +153,9 @@ const notebooks: { id: string; steps: TStep[] } = {
}}
>
<Heading size={SIZE.md} color={colors.primary.heading}>
Work and office
{strings.workAndOffice()}
</Heading>
<Paragraph>Everything related to my job in one place.</Paragraph>
<Paragraph>{strings.workAndOfficeDesc()}</Paragraph>
<Paragraph
style={{
@@ -165,7 +164,7 @@ const notebooks: { id: string; steps: TStep[] } = {
size={SIZE.xs}
color={colors.secondary.paragraph}
>
Notebook - 2 notes
{strings.notes(2)}
</Paragraph>
</View>
<View
@@ -184,7 +183,7 @@ const notebooks: { id: string; steps: TStep[] } = {
size={SIZE.sm}
name="bookmark"
/>{" "}
Tasks
{strings.tasks()}
</Paragraph>
</View>
<View
@@ -200,7 +199,7 @@ const notebooks: { id: string; steps: TStep[] } = {
>
<Paragraph size={SIZE.xs}>
<Icon color={colors.primary.icon} size={SIZE.sm} name="note" />{" "}
February 2022 Week 2
{strings.taskAValue()}
</Paragraph>
</View>
<View
@@ -216,7 +215,7 @@ const notebooks: { id: string; steps: TStep[] } = {
>
<Paragraph size={SIZE.xs}>
<Icon color={colors.primary.icon} size={SIZE.sm} name="note" />{" "}
February 2022 Week 1
{strings.taskBValue()}
</Paragraph>
</View>
<View
@@ -235,19 +234,19 @@ const notebooks: { id: string; steps: TStep[] } = {
size={SIZE.sm}
name="bookmark"
/>{" "}
Meetings
{strings.meetings()}
</Paragraph>
</View>
</View>
),
button: {
type: "next",
title: "Next"
title: strings.next()
}
},
{
title: "Easy access",
text: "You can create shortcuts of frequently accessed notebooks in the side menu",
title: strings.easyAccess(),
text: strings.easyAccessDesc(),
walkthroughItem: () => (
<View
style={{
@@ -256,29 +255,31 @@ const notebooks: { id: string; steps: TStep[] } = {
}}
>
<PinItem
index={0}
placeholder={true}
item={{
title: "Tasks",
type: "topic"
}}
isPlaceholder={true}
item={
{
title: strings.tasks(),
type: "notebook"
} as Notebook
}
onPress={() => {}}
/>
<PinItem
index={1}
placeholder={true}
item={{
title: "Work and office",
isPlaceholder={true}
item={
{
title: strings.workAndOffice(),
type: "notebook"
}}
} as Notebook
}
onPress={() => {}}
/>
</View>
),
button: {
type: "done",
title: "Add your first notebook",
title: strings.addFirstNotebook(),
action: () => {
eSendEvent(eOpenAddNotebookDialog);
}
@@ -287,67 +288,32 @@ const notebooks: { id: string; steps: TStep[] } = {
]
};
const ChooseTheme = () => {
return (
<View
style={{
alignItems: "center",
marginTop: 20
}}
>
<Heading>Make yourself at home</Heading>
<Paragraph
style={{
textAlign: "center",
alignSelf: "center",
maxWidth: "80%"
}}
size={SIZE.md}
>
Pick a theme of your choice
</Paragraph>
<Seperator />
<AccentColorPicker />
<Seperator />
</View>
);
};
const trialstarted: { id: string; steps: TStep[] } = {
id: "trialstarted",
steps: [
{
title: "Your trial is activated",
text: "You can use all premium features for free for the next 14 days",
title: strings.trialStarted(),
text: strings.trialStartedDesc(),
walkthroughItem: (colors) => (
<SvgView src={LAUNCH_ROCKET(colors.primary.paragraph)} />
),
button: {
type: "next",
title: "Next"
}
},
{
walkthroughItem: () => <ChooseTheme />,
button: {
type: "next",
title: "Next"
title: strings.next()
}
},
{
title: "Join the cause",
text: "Meet other privacy-minded people and talk to us directly about your concerns, issues and suggestions.",
title: strings.joinTheCause(),
text: strings.meetPrivacyMinded(),
walkthroughItem: (colors) => (
<SvgView src={COMMUNITY_SVG(colors.primary.paragraph)} />
),
button: {
type: "done",
title: "Continue"
title: strings.continue()
},
actionButton: {
text: "Join Discord Community",
text: strings.joinDiscord(),
action: () => {
Linking.openURL("https://discord.gg/zQBK97EE22").catch(console.log);
}
@@ -360,14 +326,14 @@ const emailconfirmed: { id: string; steps: TStep[] } = {
id: "emailconfirmed",
steps: [
{
title: "Email confirmed",
text: "Your email was confirmed successfully. Thank you for choosing end-to-end encrypted note taking.",
title: strings.emailConfirmed(),
text: strings.emailNotConfirmedDesc(),
walkthroughItem: (colors) => (
<SvgView src={WELCOME_SVG(colors.primary.paragraph)} />
),
button: {
type: "done",
title: "Continue"
title: strings.continue()
}
}
]
@@ -382,15 +348,14 @@ const Support = () => {
}}
>
<SvgView src={SUPPORT_SVG()} />
<Heading>Get Priority Support</Heading>
<Heading>{strings.prioritySupport()}</Heading>
<Paragraph
style={{
textAlign: "center"
}}
size={SIZE.md}
>
You can reach out to us via multiple channels if you face an issue or
want to just talk.
{strings.weAreAlwaysListening()}
</Paragraph>
<Seperator />
@@ -405,7 +370,7 @@ const Support = () => {
}}
icon="discord"
type="secondary"
title="Join our community on Discord"
title={strings.joinDiscord()}
/>
<Button
@@ -419,7 +384,7 @@ const Support = () => {
}}
icon="telegram"
type="secondary"
title="Join our Telegram group"
title={strings.joinTelegram()}
/>
<Button
style={{
@@ -429,7 +394,7 @@ const Support = () => {
}}
icon="bug"
type="secondary"
title="Submit an issue from Settings"
title={strings.reportAnIssue()}
/>
<Button
style={{
@@ -439,7 +404,7 @@ const Support = () => {
}}
icon="mail"
type="secondary"
title="Email us at support@streetwriters.co"
title={strings.emailSupport()}
/>
</View>
);
@@ -449,21 +414,21 @@ const prouser: { id: string; steps: TStep[] } = {
id: "prouser",
steps: [
{
title: "Welcome to Notesnook Pro",
text: "Thank you for reaffirming our idea that privacy comes first",
title: strings.welcomeToNotesnookPro(),
text: strings.thankYouPrivacy(),
walkthroughItem: (colors) => (
<SvgView src={LAUNCH_ROCKET(colors.primary.paragraph)} />
),
button: {
type: "next",
title: "Next"
title: strings.next()
}
},
{
walkthroughItem: () => <Support />,
button: {
type: "done",
title: "Continue"
title: strings.continue()
}
}
]

View File

@@ -146,15 +146,16 @@ const Editor = React.memo(
onRenderProcessGone={onError}
nestedScrollEnabled
onError={onError}
injectedJavaScriptBeforeContentLoaded={`
globalThis.LINGUI_LOCALE = "${i18n.locale}";
globalThis.LINGUI_LOCALE_DATA = ${JSON.stringify({
[i18n.locale]: i18n.messages
})};
injectedJavaScript={`
globalThis.__DEV__ = ${__DEV__}
globalThis.readonly=${readonly};
globalThis.noToolbar=${noToolbar};
globalThis.noHeader=${noHeader};
globalThis.LINGUI_LOCALE = "${i18n.locale}";
globalThis.LINGUI_LOCALE_DATA = ${JSON.stringify({
[i18n.locale]: i18n.messages
})};
globalThis.loadApp();
`}
useSharedProcessPool={false}
javaScriptEnabled={true}

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { formatBytes, getFormattedDate } from "@notesnook/common";
import { LegacyBackupFile } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useState } from "react";
import { ActivityIndicator, FlatList, Platform, View } from "react-native";
@@ -46,7 +47,6 @@ import SettingsService from "../../../services/settings";
import { refreshAllStores } from "../../../stores/create-db-collection-store";
import { useUserStore } from "../../../stores/use-user-store";
import { SIZE } from "../../../utils/size";
import { strings } from "@notesnook/intl";
type PasswordOrKey = { password?: string; encryptionKey?: string };
@@ -533,12 +533,11 @@ const BackupItem = ({
}}
onPress={() => {
presentDialog({
title: `Restore ${itemName}`,
paragraph: `Are you sure you want to restore this backup?`,
positiveText: "Restore",
negativeText: "Cancel",
title: `${strings.restore()} ${itemName}`,
paragraph: strings.restoreBackupConfirm(),
positiveText: strings.restore(),
negativeText: strings.cancel(),
positivePress: async () => {
console.log("file path", (item as ScopedStorage.FileType).uri);
restoreBackup({
uri:
Platform.OS === "android"

View File

@@ -145,14 +145,16 @@ export function ServersConfiguration() {
.catch(() => undefined);
if (!version)
throw new Error(
`${strings.couldNotConnectTo()} ${server.title}.`
`${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(strings.serverVersionMismatch());
throw new Error(
strings.serverVersionMismatch(server.title, url)
);
}
}
setSuccess(true);

View File

@@ -339,21 +339,21 @@ export const settingsGroups: SettingSection[] = [
presentDialog({
title: strings.clearCacheConfirm(),
paragraph: strings.clearCacheConfirmDesc(),
positiveText: "Clear",
positiveText: strings.clear(),
positivePress: async () => {
filesystem.clearCache();
ToastManager.show({
heading: "Cache cleared",
message: "All cached attachments have been removed",
heading: strings.cacheCleared(),
message: strings.cacheClearedDesc(),
type: "success"
});
}
});
},
description(current) {
return `${strings.clearCacheDesc()}. Current cache size: ${
current as number
}`;
return `${strings.clearCacheDesc()}. ${strings.currentCacheSize(
`${current}`
)}`;
},
useHook: () => {
const [cacheSize, setCacheSize] = React.useState(0);
@@ -380,7 +380,7 @@ export const settingsGroups: SettingSection[] = [
presentDialog({
title: strings.logout(),
paragraph: strings.logoutConfirmation(),
positiveText: "Logout",
positiveText: strings.logout(),
check: {
info: strings.backupDataBeforeLogout(),
defaultValue: true
@@ -804,8 +804,8 @@ export const settingsGroups: SettingSection[] = [
{
id: "servers",
type: "screen",
name: "Servers",
description: "Configure server URLs for Notesnook",
name: strings.servers(),
description: strings.serversConfigurationDesc(),
icon: "server",
component: "server-config"
}

View File

@@ -33,11 +33,9 @@ import { strings } from "@notesnook/intl";
function confirmDeleteAllNotes(items, type, context) {
return new Promise((resolve) => {
presentDialog({
title: `Delete ${
items.length > 1 ? `${items.length} ${type}s` : `${type}`
}?`,
positiveText: "Delete",
negativeText: "Cancel",
title: strings.doAction("type", items.length, "delete"),
positiveText: strings.delete(),
negativeText: strings.cancel(),
positivePress: (_inputValue, value) => {
setTimeout(() => {
resolve({ delete: true, deleteNotes: value });

View File

@@ -34,7 +34,6 @@ export async function unlockVault({
paragraph: string;
}) {
if (unlockPromise) {
console.log("Unlocking.... waiting for unlock promise");
return unlockPromise;
}
unlockPromise = new Promise(async (resolve) => {
@@ -58,10 +57,10 @@ export async function unlockVault({
context: context,
input: true,
secureTextEntry: true,
positiveText: "Unlock",
positiveText: strings.unlock(),
title: title,
paragraph: paragraph,
inputPlaceholder: "Enter password",
inputPlaceholder: strings.enterPassword(),
positivePress: async (value) => {
const unlocked = await db.vault.unlock(value);
if (!unlocked) {

View File

@@ -30,6 +30,17 @@ setI18nGlobal(i18n);
i18n.activate("en");
setI18nGlobal(i18n);
if (global.__DEV__) {
const err = console.error;
console.error = function (message) {
if (typeof message === 'string' && message.includes('VirtualizedLists should never be')) {
err.apply(console, ["VirtualizedLists should never be nested inside plain ScrollViews"]);
return;
}
err.apply(console, arguments);
};
}
try {
ScriptManager.shared.addResolver(async (scriptId) => {

View File

@@ -16,6 +16,7 @@ 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 "./utils/index";
global.Buffer = require("buffer").Buffer;
import { i18n } from "@lingui/core";
import "@notesnook/editor/styles/fonts.mobile.css";
@@ -27,15 +28,30 @@ import { createRoot } from "react-dom/client";
import App from "./App";
import "./index.css";
if (globalThis.__DEV__) {
const logFn = global.console.log;
global.console.log = function () {
//@ts-ignore
logFn.apply(console, arguments);
globalThis.logger("info", ...arguments);
};
}
let appLoaded = false;
function loadApp() {
if (appLoaded) return;
appLoaded = true;
const locale = globalThis.LINGUI_LOCALE_DATA
? Promise.resolve(globalThis.LINGUI_LOCALE_DATA)
: globalThis.__DEV__ || process.env.NODE_ENV === "development"
? import("@notesnook/intl/locales/$pseudo-LOCALE.json").then(
({ default: locale }) => ({ en: locale.messages })
)
: import("@notesnook/intl/locales/$en.json").then(({ default: locale }) => ({
: import("@notesnook/intl/locales/$en.json").then(
({ default: locale }) => ({
en: locale.messages
}));
})
);
locale.then((locale) => {
i18n.load(locale);
i18n.activate(globalThis.LINGUI_LOCALE || "en");
@@ -47,3 +63,5 @@ locale.then((locale) => {
root.render(<App />);
}
});
}
globalThis.loadApp = loadApp;

View File

@@ -59,6 +59,7 @@ declare global {
var pendingResolvers: {
[key: string]: (value: any) => void;
};
var readonlyEditor: boolean;
var statusBars: Record<
number,
@@ -141,6 +142,8 @@ declare global {
function logger(type: "info" | "warn" | "error", ...logs: unknown[]): void;
function dbLogger(type: "log" | "error", ...logs: unknown[]): void;
function loadApp(): void;
/**
* Function to post message to react native
* @param type

View File

@@ -27,7 +27,7 @@
"compile": "lingui compile --typescript",
"build-locale": "npm run extract && npm run compile",
"build": "npm run build-locale && npx vite build && node scripts/postbuild.mjs",
"watch": "nodemon --watch ./src/*.ts --exec \"npx vite build\"",
"watch": "npx vite build --watch",
"postinstall": "patch-package"
},
"devDependencies": {

View File

@@ -17,6 +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 { plural, select, t } from "@lingui/macro";
import { fail } from "assert";
const actions = {
deleted: () => t`deleted`,
@@ -42,7 +43,8 @@ const doActions = {
edit: () => t`Edit`,
create: () => t`Created`,
rename: () => t`Rename`,
remove: () => t`Remove`
remove: () => t`Remove`,
download: () => t`Download`
};
const inProgressActions = {
@@ -999,6 +1001,8 @@ $headline$: Use starting line of the note as title.`,
account: () => t`account`,
subscribeToPro: () => t`Subscribe to Pro`,
trialStarted: () => t`Your free trial has started`,
trialStartedDesc: () =>
t`You can use all premium features for free for the next 14 days`,
subDetails: () => t`Subscription details`,
signedUpOn: (date: string) => t`Signed up on ${date}`,
trialEndsOn: (date: string) => t`Your free trial ends on ${date}`,
@@ -2425,5 +2429,34 @@ Use this if changes from other devices are not appearing on this device. This wi
increase: (title: string) => t`Increase ${title}`,
decrease: (title: string) => t`Decrease ${title}`,
saved: () => t`Saved`,
saving: () => t`Saving`
saving: () => t`Saving`,
attachmentRecheckCancelled: () => t`Attachment recheck cancelled`,
recheckAll: () => t`Recheck all`,
attachmentRecheckComplete: () => t`Attachments recheck complete`,
checkingNoteAttachments: () => t`Checking note attachments`,
checkingAllAttachments: () => t`Checking all attachments`,
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`,
boostProductivityNotebook: () =>
t`Boost your productivity with Notebooks and organize your notes.`,
notebookNotes: () => t` "Notebook > Notes"`,
notebookNotesDesc: () => t`Every Notebook can have notes and sub notebooks.`,
workAndOffice: () => t`Work & Office`,
workAndOfficeDesc: () => t`Everything related to my job in one place.`,
tasks: () => t`Tasks`,
taskAValue: () => t`February 2022 Week 2`,
taskBValue: () => t`February 2022 Week 3`,
meetings: () => t`Meetings`,
easyAccess: () => t`Easy access`,
easyAccessDesc: () =>
t`You can create shortcuts of frequently accessed notebooks in the side menu`,
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.`
};