Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
74bb373
Adding selector dropdown [wip]
melissachen2000 Jan 31, 2026
267c822
Adding multilingual how-to text
melissachen2000 Feb 7, 2026
c255233
Fixing locale duplicates, map construction
melissachen2000 Feb 7, 2026
6e8ab59
Fix writing in a new language
melissachen2000 Feb 7, 2026
d6c091c
Fixed default language + which locales are stored on the how-to
melissachen2000 Feb 7, 2026
e992a35
Adding translations to title
melissachen2000 Feb 7, 2026
9cdbbd6
Multilingual titles in preview, announcer
melissachen2000 Feb 7, 2026
8684122
Merge remote-tracking branch 'upstream/main' into how-to-translation
melissachen2000 Feb 7, 2026
b2a9708
Handle legacy cases
melissachen2000 Feb 7, 2026
b182cf0
Three letter language code
melissachen2000 Feb 7, 2026
738ec2a
Fix regex
melissachen2000 Feb 7, 2026
2025fa5
Moving markup-map converters to how-to class, clean up code
melissachen2000 Feb 7, 2026
79e638b
Merge remote-tracking branch 'upstream/main' into how-to-translation
melissachen2000 Feb 7, 2026
6f4ef32
Changing regex to match multiline documentation
melissachen2000 Feb 7, 2026
f0e13da
Change fallback logic for title of how-to in announcer
melissachen2000 Feb 7, 2026
3d6be0a
Adding gallery access check for moderation notifications
melissachen2000 Feb 8, 2026
bf9154e
Minor style updates.
amyjko Feb 8, 2026
3b54b75
Merge pull request #946 from melissachen2000/945-gallery-permissions-…
amyjko Feb 8, 2026
bd39e4e
Merge remote-tracking branch 'upstream/main' into how-to-translation
melissachen2000 Feb 8, 2026
9db6cd4
Fixing regex for language detection, look up filler title by locale
melissachen2000 Feb 8, 2026
79d02f9
Changing regex to pull from supported locales
melissachen2000 Feb 8, 2026
5822d39
Changing key of title placeholder, was confusing due to name
melissachen2000 Feb 8, 2026
ba4e2d9
Make language select refresh on UI language change, resolve bug with …
melissachen2000 Feb 8, 2026
a71d5d1
Fix type error with title
melissachen2000 Feb 8, 2026
762aac8
Fix default JSON formatter in VSCode
melissachen2000 Feb 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/components/settings/Notifications.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@
if (howTo) galleryID = howTo.getHowToGalleryId();
}

if (!galleryID) return;
// No gallery, or creator doesn't have access to gallery? No need for notifications.
if (
galleryID === null ||
!Galleries.accessibleGalleries.has(galleryID)
)
return;

const gallery = await Galleries.get(galleryID);
chat.getMessagesPendingModeration($user.uid, gallery).forEach(
Expand All @@ -114,7 +119,7 @@
: howTo
? howTo.getTitle()
: '',
galleryID: galleryID ? galleryID : undefined,
galleryID,
itemID: itemID,
type: type,
} as NotificationData);
Expand Down
83 changes: 82 additions & 1 deletion src/db/howtos/HowToDatabase.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { NotificationData } from '@components/settings/Notifications.svelte
import { type Database } from '@db/Database';
import { firestore } from '@db/firebase';
import type Gallery from '@db/galleries/Gallery';
import { SupportedLocales } from '@locale/SupportedLocales';
import { FirebaseError } from 'firebase/app';
import {
and,
Expand Down Expand Up @@ -152,6 +153,21 @@ export default class HowTo {
return this.data.title;
}

getTitleAsMap(): SvelteMap<string, string[]> {
return this.markupToMapHelper([this.data.title]);
}

/** Get the title of the how-to in the specified locale. If there is no title written in that language, fall back to the first title */
getTitleInLocale(locale: string): string {
const titleMap = this.getTitleAsMap();
let nameInLocale: string[] | undefined = titleMap.get(locale);
if (nameInLocale) return nameInLocale[0];

let firstLanguage: [string, string[]] | undefined = titleMap.entries().next().value;
if (firstLanguage) return firstLanguage[1][0];
else return ''; // fall back to an empty title
}

getGuidingQuestions() {
return this.data.guidingQuestions;
}
Expand All @@ -160,6 +176,71 @@ export default class HowTo {
return this.data.text;
}

private markupToMapHelper(markup: string[]): SvelteMap<string, string[]> {
// input format: ['¶hello¶/en-US¶hola¶/es-MX', '¶bye¶/en-US¶adios¶/es-MX']
// output format: {'en-US': ['hello', 'bye'], 'es-MX': ['hola', 'adios']}
let map: SvelteMap<string, string[]> = new SvelteMap<
string,
string[]
>();

// should match strings in the format of "¶some text¶/locale", where the locale is one of the supported locales
// necessary, since not all locales match the {2,3}-{2,3} format (e.g., ta-IN-LK-SG)
let regexString: string = "¶(.*?)¶\/(" + SupportedLocales.join("|") + ")";
let regex: RegExp = new RegExp(regexString, "gs");

markup.forEach((m) => {
let stringAndLocale: RegExpExecArray[] = [...m.matchAll(regex)];

// dealing with cases of no markup, just text (i.e., how-to was created before translation was implemented)
// 'en-US' was the hard-coded default locale, so we just use that
if (stringAndLocale.length === 0) {
map.set('en-US', [m]);
return;
}

stringAndLocale.forEach((match) => {
let locale: string = match[2];
let text: string = match[1];

if (map.has(locale)) {
map.get(locale)?.push(text);
} else {
map.set(locale, [text]);
}
});
});

return map;
}

/** Converts the text of the how-to in to a map of locales to string lists (for each) */
getTextAsMap(): SvelteMap<string, string[]> {
return this.markupToMapHelper(this.data.text);
}

/** Converts the map of locales to string lists back to the text format of the how-to (first return value is a list of locales) */
static mapToMarkupHelper(userInput: SvelteMap<string, string[]>,
length: number
): [string[], string[]] {
let usedLocales: Set<string> = new Set<string>();
let markupTexts: string[] = Array(length).fill('');

// input format: {'en-US': ['hello', 'bye'], 'es-MX': ['hola', 'adios']}
// output format: ['¶hello¶/en-US¶hola¶/es-MX', '¶bye¶/en-US¶adios¶/es-MX']
// also need to account for code, e.g., "some text, \Phrase('some code')\" --> "¶some text, ¶\Phrase('some code')\/en-US"
userInput.entries().forEach(([locale, text]) => {
if (text.every((t) => t.length === 0)) return; // if all the text for this locale is empty, skip it

usedLocales.add(locale);
text.forEach((str, i) => {
markupTexts[i] += `¶${str}¶/${locale}`;
});
});

return [[...usedLocales], markupTexts];
};

getCreator() {
return this.data.creator;
}
Expand All @@ -183,7 +264,7 @@ export default class HowTo {
return this.data.viewersFlat.includes(userId);
}

getLocales() {
getLocales(): string[] {
return this.data.locales;
}

Expand Down
5 changes: 3 additions & 2 deletions src/locale/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -4558,12 +4558,13 @@
"description": "the title of your how-to",
"placeholder": "Title"
},
"titlePlaceholder": "Untitled how-to",
"untitledHowToPlaceholder": "Untitled how-to",
"collaboratorsPrompt": "Add a collaborator, who can edit this how-to",
"collaboratorsToggle": {
"on": "collapse the collaborators panel",
"off": "expand the collaborators panel"
}
},
"localeOptionsLabel": "editor input language"
},
"viewer": {
"view": {
Expand Down
2 changes: 1 addition & 1 deletion src/routes/gallery/[galleryid]/howto/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@
.map((h) => {
return {
value: h.getHowToId(),
label: h.getTitle(),
label: h.getTitleInLocale($locales.getLocaleString()),
};
})
.sort((a, b) => a.label.localeCompare(b.label)),
Expand Down
Loading