Skip to content

Commit

Permalink
Fixed #181, localizing default galleries.
Browse files Browse the repository at this point in the history
  • Loading branch information
amyjko committed Oct 22, 2023
1 parent 36dd423 commit a96b2e8
Show file tree
Hide file tree
Showing 18 changed files with 371 additions and 125 deletions.
7 changes: 5 additions & 2 deletions src/components/app/CreatorView.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import type { Creator } from '@db/CreatorDatabase';
import { locales } from '@db/Database';
import { HiddenUsernameEmailDomain } from '../../db/Creator';
export let creator: Creator | null;
export let anonymize = true;
Expand All @@ -14,8 +15,10 @@
>{/if}{creator
? creator.email === null
? ''
: anonymize || creator.email.endsWith('@wordplay.dev')
? creator.email.split('@')[0].substring(0, 4)
: anonymize
? `${creator.email.split('@')[0].substring(0, 4)}...`
: creator.email.endsWith(HiddenUsernameEmailDomain)
? creator.email.replace(HiddenUsernameEmailDomain, '')
: creator.email
: $locales.get((l) => l.ui.page.login.anonymous)}</div
>
Expand Down
7 changes: 2 additions & 5 deletions src/components/app/GalleryPreview.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@

<div class="gallery">
<Link to={`gallery/${gallery.getID()}`}
><Subheader>{gallery.getName($locales.getLocale())}</Subheader></Link
><Subheader>{gallery.getName($locales)}</Subheader></Link
>
<MarkupHtmlView
markup={gallery
.getDescription($locales.getLocale())
.split('\n')
.join('\n\n')}
markup={gallery.getDescription($locales).split('\n').join('\n\n')}
/>
<!-- We have to guard this since we haven't structured the project database to run server side fetches, so SvelteKit builds fail. -->
{#if browser}
Expand Down
2 changes: 1 addition & 1 deletion src/components/project/Collaborators.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
...Array.from($creatorGalleries.values()).map((gallery) => {
return {
value: get(gallery).getID(),
label: get(gallery).getName($locales.getLocale()),
label: get(gallery).getName($locales),
};
}),
]}
Expand Down
2 changes: 2 additions & 0 deletions src/db/Creator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const HiddenUsernameEmailDomain = '@wordplay.dev';

export type Creator = {
icon: string;
};
20 changes: 17 additions & 3 deletions src/db/GalleryDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { FirebaseError } from 'firebase/app';
import { get, writable, type Writable } from 'svelte/store';
import type Project from '../models/Project';
import { toLocaleString } from '../locale/Locale';
import { ExampleGalleries } from '../examples/examples';
import { getExampleGalleries } from '../examples/examples';
import type Locales from '../locale/Locales';

export default class GalleryDatabase {
Expand All @@ -39,6 +39,9 @@ export default class GalleryDatabase {
readonly status: Writable<'loading' | 'noaccess' | 'loggedout' | 'loaded'> =
writable('loading');

/** Example hard coded galleries */
readonly exampleGalleries: Writable<Gallery[]> = writable([]);

/** Public galleries that have been loaded individually. */
readonly publicGalleries: Map<string, Writable<Gallery>> = new Map();

Expand All @@ -49,9 +52,20 @@ export default class GalleryDatabase {
this.database = database;

// Add the example galleries to the database.
for (const gallery of ExampleGalleries) {
const examples = getExampleGalleries(database.Locales.getLocaleSet());
for (const gallery of examples)
this.publicGalleries.set(gallery.getID(), writable(gallery));
}
this.exampleGalleries.set(examples);

// When the list of locales change, recreate the galleries with the new locales.
database.Locales.locales.subscribe((locales) => {
// Udpate each gallery store with the new localized gallery.
const localizedExamples = getExampleGalleries(locales);
for (const gallery of localizedExamples)
this.publicGalleries.get(gallery.getID())?.set(gallery);
// Update the list of example galleries.
this.exampleGalleries.set(localizedExamples);
});

this.listen();
}
Expand Down
98 changes: 64 additions & 34 deletions src/examples/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { parseNames } from '../parser/parseBind';
import { toTokens } from '../parser/toTokens';
import Gallery from '../models/Gallery';
import { moderatedFlags } from '../models/Moderation';
import type Locales from '../locale/Locales';
import { toLocaleString } from '../locale/Locale';
import type { GalleryText } from '../locale/GalleryTexts';

/** This mirrors the static path to examples, but also helps distinguish project IDs from example project names. */
export const ExamplePrefix = 'example-';
Expand Down Expand Up @@ -66,12 +69,20 @@ export async function getExample(
}
}

function createGallery(name: string, description: string, projects: string[]) {
function createGallery(
id: string,
text: Record<string, GalleryText>,
projects: string[]
) {
return new Gallery({
id: name,
path: name,
name: { 'en-US': name },
description: { 'en-US': description },
id,
path: id,
name: Object.fromEntries(
Object.entries(text).map(([locale, t]) => [locale, t.name])
),
description: Object.fromEntries(
Object.entries(text).map(([locale, t]) => [locale, t.description])
),
words: [],
projects: projects.map((name) => ExamplePrefix + name),
curators: [],
Expand All @@ -81,32 +92,51 @@ function createGallery(name: string, description: string, projects: string[]) {
});
}

export const ExampleGalleries: Gallery[] = [
createGallery('Games', 'Simple interactive games that play with words.', [
'Adventure',
'Maze',
'WhatWord',
'Catch',
]),
createGallery('Visualizations', 'Visualizations that celebrate language.', [
'Amplitude',
'Garden',
'Letters',
'Poem',
'Questions',
'RainingKitties',
'RotatingBinary',
]),
createGallery('Physics', 'Demonstrations of physics.', [
'Hira',
'Layers',
'Pounce',
]),
createGallery('Sound', 'Demonstrations of audio and video input.', [
'Listen',
'Talk',
'RainingLetters',
'Video',
]),
createGallery('Tools', 'Simple utilities.', ['Timer', 'Headlines']),
];
export function getExampleGalleries(locales: Locales): Gallery[] {
const locale = locales.getLocales();
return [
createGallery(
'Games',
Object.fromEntries(
locale.map((l) => [toLocaleString(l), l.gallery.games])
),
['Adventure', 'Maze', 'WhatWord', 'Catch']
),
createGallery(
'Visualizations',
Object.fromEntries(
locale.map((l) => [toLocaleString(l), l.gallery.visualizations])
),
[
'Amplitude',
'Garden',
'Letters',
'Poem',
'Questions',
'RainingKitties',
'RotatingBinary',
]
),
createGallery(
'Motion',
Object.fromEntries(
locale.map((l) => [toLocaleString(l), l.gallery.motion])
),
['Hira', 'Layers', 'Pounce']
),
createGallery(
'AV',
Object.fromEntries(
locale.map((l) => [toLocaleString(l), l.gallery.av])
),
['Listen', 'Talk', 'RainingLetters', 'Video']
),
createGallery(
'Tools',
Object.fromEntries(
locale.map((l) => [toLocaleString(l), l.gallery.tools])
),
['Timer', 'Headlines']
),
];
}
12 changes: 12 additions & 0 deletions src/locale/GalleryTexts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type GalleryText = {
name: string;
description: string;
};

export type GalleryTexts = {
games: GalleryText;
visualizations: GalleryText;
motion: GalleryText;
av: GalleryText;
tools: GalleryText;
};
3 changes: 3 additions & 0 deletions src/locale/Locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { DOCS_SYMBOL } from '../parser/Symbols';
import type { FlagDescriptions } from '../models/Moderation';
import type { ButtonText, DialogText } from './UITexts';
import type Locales from './Locales';
import type { GalleryTexts } from './GalleryTexts';

/** A list of locales that are in progress but not supported yet. Only added when developing locally. */
const EventuallySupportedLocales = ['zh-CN'];
Expand Down Expand Up @@ -66,6 +67,8 @@ export type Locale = {
output: OutputTexts;
/** User interface strings */
ui: UITexts;
/** Default gallery text */
gallery: GalleryTexts;
/** Text related to content moderation */
moderation: {
/** What to say to warn viewers before showing content with warnings. */
Expand Down
22 changes: 22 additions & 0 deletions src/locale/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -4321,5 +4321,27 @@
"label": "skip"
}
}
},
"gallery": {
"games": {
"name": "Games",
"description": "Interactive games with words and symbols."
},
"visualizations": {
"name": "Visualizations",
"description": "Visualizations of and via text."
},
"motion": {
"name": "Motion",
"description": "Examples of movement and collisions."
},
"av": {
"name": "Audio/Video",
"description": "Using volume, pitch, and video as input."
},
"tools": {
"name": "Tools",
"description": "Simple utilities and applications."
}
}
}
16 changes: 5 additions & 11 deletions src/models/Gallery.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type Locale from '../locale/Locale';
import { toLocaleString } from '../locale/Locale';
import type Locales from '../locale/Locales';

/** The schema for a gallery */
export type SerializedGallery = {
Expand Down Expand Up @@ -43,12 +44,8 @@ export default class Gallery {
}

/** Get the best name given a locale */
getName(locale: Locale) {
// Is there a name for this specific locale and region? If not, choose the first one.
return (
this.data.name[toLocaleString(locale)] ??
Object.values(this.data.name)[0]
);
getName(locales: Locales) {
return locales.get((l) => this.data.name[toLocaleString(l)]);
}

withName(name: string, locale: Locale) {
Expand All @@ -59,12 +56,9 @@ export default class Gallery {
}

/** Get the best description given a locale */
getDescription(locale: Locale) {
getDescription(locales: Locales) {
// Is there a name for this specific locale and region? If not, choose the first one.
return (
this.data.description[toLocaleString(locale)] ??
Object.values(this.data.description)[0]
);
return locales.get((l) => this.data.description[toLocaleString(l)]);
}

withDescription(name: string, locale: Locale) {
Expand Down
13 changes: 8 additions & 5 deletions src/routes/galleries/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import Header from '@components/app/Header.svelte';
import Writing from '@components/app/Writing.svelte';
import { locales } from '@db/Database';
import { Galleries, locales } from '@db/Database';
import MarkupHtmlView from '../../components/concepts/MarkupHTMLView.svelte';
import { onMount } from 'svelte';
import {
Expand All @@ -21,12 +21,13 @@
import GalleryPreview from '../../components/app/GalleryPreview.svelte';
import Spinning from '../../components/app/Spinning.svelte';
import Button from '../../components/widgets/Button.svelte';
import { ExampleGalleries } from '../../examples/examples';
let lastBatch: QueryDocumentSnapshot<DocumentData>;
const examples = Galleries.exampleGalleries;
/** Start the list of galleries with the example galleries. */
let galleries: Gallery[] = ExampleGalleries.slice();
let loadedGalleries: Gallery[] = [];
onMount(async () => {
nextBatch();
Expand Down Expand Up @@ -56,13 +57,15 @@
lastBatch = documentSnapshots.docs[documentSnapshots.docs.length - 1];
// Convert the docs to galleries
galleries = [
...(galleries ?? []),
loadedGalleries = [
...(loadedGalleries ?? []),
...documentSnapshots.docs.map(
(snap) => new Gallery(snap.data() as SerializedGallery)
),
];
}
$: galleries = [...$examples, ...loadedGalleries];
</script>

<svelte:head>
Expand Down
4 changes: 2 additions & 2 deletions src/routes/gallery/[galleryid]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
onDestroy(() => pageUnsubscribe());
$: name = gallery?.getName($locales.getLocale());
$: description = gallery?.getDescription($locales.getLocale());
$: name = gallery?.getName($locales);
$: description = gallery?.getDescription($locales);
$: editable = gallery
? $user !== null && gallery.getCurators().includes($user.uid)
: false;
Expand Down
5 changes: 3 additions & 2 deletions src/routes/login/Login.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import Subheader from '../../components/app/Subheader.svelte';
import MarkupHtmlView from '../../components/concepts/MarkupHTMLView.svelte';
import Note from '../../components/widgets/Note.svelte';
import { HiddenUsernameEmailDomain } from '../../db/Creator';
let user = getUser();
let success: boolean | undefined = undefined;
Expand Down Expand Up @@ -102,12 +103,12 @@
}
async function startUsernameLogin() {
const emailUsername = `${username}@wordplay.dev`;
const emailUsername = `${username}${HiddenUsernameEmailDomain}`;
if (auth && usernameSubmittable) {
try {
await signInWithEmailAndPassword(
auth,
`${username}@wordplay.dev`,
`${username}${HiddenUsernameEmailDomain}`,
password
);
} catch (error) {
Expand Down
Loading

0 comments on commit a96b2e8

Please sign in to comment.