Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
983 changes: 914 additions & 69 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"node": ">=16"
},
"scripts": {
"dev": "vite dev",
"dev": "vite",
"vite": "vite dev",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be removed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, I was testing different libraries so I did the following changes. I'll make it back to the original.

"build": "node build.js",
"preview": "vite preview",
"sync": "svelte-kit sync",
Expand All @@ -15,7 +16,8 @@
"test": "vitest run",
"test:ui": "vitest --ui",
"test:watch": "vitest watch",
"e2e": "playwright test tests/e2e"
"e2e": "playwright test tests/e2e",
"typesafe-i18n": "typesafe-i18n"
},
"dependencies": {
"@analytics/google-analytics": "^1.0.5",
Expand All @@ -27,6 +29,8 @@
"analytics": "^0.8.1",
"dotenv": "^16.0.3",
"echarts": "^5.4.1",
"i18next": "^22.5.0",
"i18next-resources-to-backend": "^1.1.4",
"logrocket": "^3.0.1",
"pretty-bytes": "^6.1.0",
"prismjs": "^1.29.0",
Expand Down
78 changes: 78 additions & 0 deletions src/lib/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import i18next from 'i18next';
import type { i18n } from 'i18next';
import { writable, type Readable, type Writable } from 'svelte/store';
import resourcesToBackend from 'i18next-resources-to-backend';

export const supportedLanguages = ['de', 'en'];

interface TranslationService {
i18n: Readable<i18n>;
}

export const isLoading = writable(true);

export class I18NextTranslationStore implements TranslationService {
public i18n: Readable<i18n>;
public isLoading: Writable<boolean>;

constructor(i18n: i18n) {
this.i18n = this.createInstance(i18n);
this.isLoading = this.createLoadingInstance(i18n);
}

private createInstance(i18n: i18n): Writable<i18n> {
const i18nWritable = writable(i18n);

i18n.on('initialized', () => {
i18nWritable.set(i18n);
});
i18n.on('loaded', () => {
i18nWritable.set(i18n);
});
i18n.on('added', () => i18nWritable.set(i18n));
i18n.on('languageChanged', () => {
i18nWritable.set(i18n);
});
return i18nWritable;
}

private createLoadingInstance(i18n: i18n): Writable<boolean> {
// if loaded resources are empty || {}, set loading to true
i18n.on('loaded', (resources) => {
Object.keys(resources).length !== 0 && isLoading.set(false);
});

// if resources failed loading, set loading to true
i18n.on('failedLoading', () => {
isLoading.set(true);
});

return isLoading;
}
}

export const createI18nStore = () => {
i18next
.use(
resourcesToBackend((language, _namespace, callback) => {
import(`$lib/translations/${language}.json`)
.then((resources) => {
callback(null, resources);
})
.catch((error) => {
callback(error, null);
});
})
)
.init({
// lng: 'de',
lng: window.navigator.language,
fallbackLng: 'en'
});

const i18nStore = new I18NextTranslationStore(i18next);

return i18nStore.i18n;
};

export const _ = createI18nStore();
63 changes: 63 additions & 0 deletions src/lib/translations/de.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"globals": {
"placeholders": {
"email": "E-Mail",
"password": "Passwort",
"enter_password": "Passwort eingeben",
"confirm_password": "Passwort bestätigen",
"your_name": "Ihr Name",
"your_email": "Ihre E-Mail-Adresse",
"your_password": "Ihr Passwort",
"your_code": "dein Code"
},
"update": "aktualisieren",
"recover": "genesen",
"accept": "akzeptieren",
"cancel": "stornieren"
},
"login": {
"title": "anmelden",
"field_inputs": {
"email": "E-Mail",
"password": "Passwort"
}
},
"sign_up": {
"title": "Anmeldung",
"field_inputs": {
"name": "Name",
"email": "E-Mail",
"password": "Passwort",
"code": "Code"
},
"already_registered": "Sie haben bereits ein Konto?"
},
"password_recovery": {
"title": "Passwort-Wiederherstellung",
"forgot_password": "Passwort vergessen",
"field_inputs": {
"email": "E-Mail",
"new_password": "Neues Kennwort",
"cnf_password": "Bestätige das Passwort"
}
},
"accept_invite": {
"title": "Einladung annehmen",
"invalid_invite": "Ungültige Einladung",
"invite": "einladen",
"sign_up": "Melden Sie sich bei Appwrite an",
"warning_alert": {
"title": "Der Einladungslink ist ungültig",
"sub_title": "Bitten Sie den Projektinhaber, Ihnen eine neue Einladung zu senden."
},
"success_alert": {
"title": "Sie wurden eingeladen, an einem Teamprojekt auf Appwrite teilzunehmen"
}
},
"privacy_and_policy": {
"main_text": "Indem Sie die Einladung annehmen, erklären Sie sich damit einverstanden",
"terms_and_condition": "Geschäftsbedingungen",
"and": "Und",
"privacy_policy": "Datenschutz und Richtlinien"
}
}
63 changes: 63 additions & 0 deletions src/lib/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"globals": {
"placeholders": {
"email": "Email",
"password": "Password",
"enter_password": "Enter Password",
"confirm_password": "Confirm Password",
"your_name": "Your name",
"your_email": "Your email",
"your_password": "Your password",
"your_code": "Your code"
},
"update": "Update",
"recover": "Recover",
"accept": "Accept",
"cancel": "Cancel"
},
"login": {
"title": "Sign in",
"field_inputs": {
"email": "Email",
"password": "Password"
}
},
"sign_up": {
"title": "Sign up",
"field_inputs": {
"name": "Name",
"email": "Email",
"password": "Password",
"code": "code"
},
"already_registered": "Already got an account?"
},
"password_recovery": {
"title": "Password Recovery",
"forgot_password": "Forgot Password",
"field_inputs": {
"email": "Email",
"new_password": "New password",
"cnf_password": "Confirm password"
}
},
"accept_invite": {
"title": "Accept invite",
"invalid_invite": "Invalid invite",
"invite": "Invite",
"sign_up": "Sign up to Appwrite",
"warning_alert": {
"title": "The invite link is not valid",
"sub_title": "Please ask the project owner to send you a new invite."
},
"success_alert": {
"title": "You have been invited to join a team project on Appwrite"
}
},
"privacy_and_policy": {
"main_text": "By accepting the invitation, you agree to the",
"terms_and_condition": "Terms and Conditions",
"and": "and",
"privacy_policy": "Privacy and Policy"
}
}
5 changes: 5 additions & 0 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@
}
}
}
// $: {
// const getUserLanguage = window.navigator.language;
// console.log(getUserLanguage);
// }
Comment on lines +111 to +114
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, how is language initialized and changed in this implementation?

</script>

<Notifications />
Expand Down
30 changes: 17 additions & 13 deletions src/routes/invite/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { onMount } from 'svelte';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { Alert } from '$lib/components';
import { _ } from '$lib/i18n';
let teamId: string, membershipId: string, userId: string, secret: string;
let terms = false;
Expand Down Expand Up @@ -40,28 +41,29 @@
</script>

<svelte:head>
<title>Accept invite - Appwrite</title>
<title>{$_.t('accept_invite.title')} - Appwrite</title>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot, is this typesafe? E.g. if I pass in a string that doesn't exist, will the IDE (not the server) return an error?

Copy link
Author

@goswamianshuman goswamianshuman Jul 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TGlide I think now we are working with pull request #459, so we have stopped working on this PR we can close this PR, but firstly we need to discuss it with @TorstenDittmann.

</svelte:head>

<Unauthenticated>
<svelte:fragment slot="title">
{#if !userId || !secret || !membershipId || !teamId}
Invalid invite
{$_.t('accept_invite.invalid_invite')}
{:else}
Invite
{$_.t('accept_invite.invite')}
{/if}
</svelte:fragment>
<svelte:fragment>
{#if !userId || !secret || !membershipId || !teamId}
<Alert type="warning">
<svelte:fragment slot="title">The invite link is not valid</svelte:fragment>
Please ask the project owner to send you a new invite.
<svelte:fragment slot="title"
>{$_.t('accept_invite.warning_alert.title')}</svelte:fragment>
{$_.t('accept_invite.warning_alert.title')}
</Alert>
<div class="u-flex u-main-end u-margin-block-start-40">
<Button href={`${base}/register`}>Sign up to Appwrite</Button>
<Button href={`${base}/register`}>{$_.t('accept_invite.sign_up')}</Button>
</div>
{:else}
<p class="text">You have been invited to join a team project on Appwrite</p>
<p class="text">{$_.t('accept_invite.success_alert.title')}</p>
<Form onSubmit={acceptInvite}>
<FormList>
<InputChoice
Expand All @@ -70,23 +72,25 @@
id="terms"
label="terms"
showLabel={false}>
By accepting the invitation, you agree to the <a
{$_.t('privacy_and_policy.main_text')}
<a
class="link"
href="https://appwrite.io/policy/terms"
target="_blank"
rel="noopener noreferrer">Terms and Conditions</a>
and
rel="noopener noreferrer"
>{$_.t('privacy_and_policy.terms_and_condition')}</a>
{$_.t('privacy_and_policy.and')}
<a
class="link"
href="https://appwrite.io/policy/privacy"
target="_blank"
rel="noopener noreferrer">
Privacy Policy</a
{$_.t('privacy_and_policy.privacy_policy')}</a
>.</InputChoice>

<div class="u-flex u-main-end u-gap-12">
<Button secondary href={`${base}/login`}>Cancel</Button>
<Button submit>Accept</Button>
<Button secondary href={`${base}/login`}>{$_.t('globals.cancel')}</Button>
<Button submit>{$_.t('globals.accept')}</Button>
</div>
</FormList>
</Form>
Expand Down
20 changes: 11 additions & 9 deletions src/routes/login/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import { Unauthenticated } from '$lib/layout';
import { Dependencies } from '$lib/constants';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { _ } from '$lib/i18n';

let mail: string, pass: string;

Expand All @@ -38,41 +39,42 @@
</script>

<svelte:head>
<title>Sign in - Appwrite</title>
<title>{$_.t('login.title')} - Appwrite</title>
</svelte:head>

<Unauthenticated>
<svelte:fragment slot="title">Sign in</svelte:fragment>
<svelte:fragment slot="title">{$_.t('login.title')}</svelte:fragment>
<svelte:fragment>
<Form onSubmit={login}>
<FormList>
<InputEmail
id="email"
label="Email"
placeholder="Email"
label={$_.t('login.field_inputs.email')}
placeholder={$_.t('globals.placeholders.email')}
autofocus={true}
required={true}
bind:value={mail} />
<InputPassword
id="password"
label="Password"
placeholder="Password"
label={$_.t('login.field_inputs.password')}
placeholder={$_.t('globals.placeholders.password')}
required={true}
meter={false}
showPasswordButton={true}
bind:value={pass} />
<FormItem>
<Button fullWidth submit>Sign in</Button>
<Button fullWidth submit>{$_.t('login.title')}</Button>
</FormItem>
</FormList>
</Form>
</svelte:fragment>
<svelte:fragment slot="links">
<li class="inline-links-item">
<a href={`${base}/recover`}><span class="text">Forgot Password?</span></a>
<a href={`${base}/recover`}
><span class="text">{$_.t('password_recovery.forgot_password')}?</span></a>
</li>
<li class="inline-links-item">
<a href={`${base}/register`}><span class="text">Sign Up</span></a>
<a href={`${base}/register`}><span class="text">{$_.t('sign_up.title')}</span></a>
</li>
</svelte:fragment>
</Unauthenticated>
Loading