From 0ebb60f986682ad8d3538c2fd1d708a861e0b1fb Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Mon, 22 Aug 2022 15:49:08 -0700 Subject: migrate to sveltekit-i18n --- src/components/404.svelte | 6 +- src/components/About.svelte | 25 ++- src/components/AppHeader.svelte | 6 +- src/components/FaqCard.svelte | 6 +- src/components/Footer.svelte | 10 +- src/components/HowItWorksCard.svelte | 6 +- src/components/LandingHeader.svelte | 30 ++-- src/components/LandingHero.svelte | 12 +- src/components/LocaleSelector.svelte | 2 +- src/components/RegisterOrLogin.svelte | 18 +- src/lib/i18n.js | 48 ----- src/lib/translations/index.js | 9 + src/lib/translations/lang.json | 4 + src/lib/translations/translations.js | 225 ++++++++++++++++++++++++ src/routes/+error.svelte | 6 +- src/routes/+layout.svelte | 15 +- src/routes/+page.svelte | 22 +-- src/routes/[username]/+page.svelte | 8 +- src/routes/[username]/dashboard/+page.svelte | 22 +-- src/routes/[username]/receive/+page.svelte | 8 +- src/routes/[username]/settings/+page.svelte | 54 +++--- src/routes/[username]/support/+page.svelte | 12 +- src/routes/[username]/transactions/+page.svelte | 14 +- src/routes/invoice/[id]/+page.svelte | 10 +- src/routes/jobs/+page.svelte | 14 +- 25 files changed, 385 insertions(+), 207 deletions(-) delete mode 100644 src/lib/i18n.js create mode 100644 src/lib/translations/index.js create mode 100644 src/lib/translations/lang.json create mode 100644 src/lib/translations/translations.js (limited to 'src') diff --git a/src/components/404.svelte b/src/components/404.svelte index 4d5be76e..08323d40 100644 --- a/src/components/404.svelte +++ b/src/components/404.svelte @@ -1,6 +1,6 @@
@@ -11,7 +11,7 @@ -

{$_('404.404')}

-

{$_('404.pageNotFound')}

+

{$t('404.404')}

+

{$t('404.pageNotFound')}

diff --git a/src/components/About.svelte b/src/components/About.svelte index db74fd96..257fc49c 100644 --- a/src/components/About.svelte +++ b/src/components/About.svelte @@ -1,22 +1,22 @@ -

{$_('about.header')}

+

{$t('about.header')}

- {@html $_('about.p1')} + {@html $t('about.p1')}

- {@html $_('about.p2')} + {@html $t('about.p2')}

- {@html $_('about.p3')} + {@html $t('about.p3')}

- {@html $_('about.p4')} + {@html $t('about.p4')}

@@ -24,17 +24,17 @@

- {$_('about.founder.header')} + {$t('about.founder.header')}

{$_('about.founder.name')}{$t('about.founder.name')} {$_('about.founder.position')}{$t('about.founder.position')}
@@ -57,16 +57,13 @@
    - {#each Object.values($json('about.founder.qualifications')) as qualification} -
  • {qualification}
  • - {/each}
-

{$_('about.locations.header')}

+

{$t('about.locations.header')}

- {@html $_('about.locations.description')} + {@html $t('about.locations.description')}

diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte index 1d24cb1d..7b3987d5 100644 --- a/src/components/AppHeader.svelte +++ b/src/components/AppHeader.svelte @@ -5,7 +5,7 @@ import { user, newPayment, colorTheme } from '$lib/store'; import { goto } from '$app/navigation'; import { Icon } from '$comp'; - import { _ } from 'svelte-i18n'; + import { t } from '$lib/translations'; export let avatarPosition = 'left-[calc(50vw-48px)]'; @@ -75,7 +75,7 @@ {/each} @@ -86,7 +86,7 @@ {:else} {$t('nav.signIn')} {/if} diff --git a/src/components/FaqCard.svelte b/src/components/FaqCard.svelte index 0d3a9fa7..918e03d6 100644 --- a/src/components/FaqCard.svelte +++ b/src/components/FaqCard.svelte @@ -1,5 +1,5 @@
-

{$_('faq.' + questionID + '.question')}

+

{$t('faq.' + questionID + '.question')}

- {$_('faq.' + questionID + '.answer')} + {$t('faq.' + questionID + '.answer')}

diff --git a/src/components/Footer.svelte b/src/components/Footer.svelte index e2acd993..a1173f74 100644 --- a/src/components/Footer.svelte +++ b/src/components/Footer.svelte @@ -1,6 +1,6 @@
-

{$_('howItWorks.' + stepID + '.header')}

+

{$t('howItWorks.' + stepID + '.header')}

- {$_('howItWorks.' + stepID + '.description')} + {$t('howItWorks.' + stepID + '.description')}

diff --git a/src/components/LandingHeader.svelte b/src/components/LandingHeader.svelte index acc83001..372c0b98 100644 --- a/src/components/LandingHeader.svelte +++ b/src/components/LandingHeader.svelte @@ -3,7 +3,7 @@ import { scroll } from '$lib/utils'; import { Icon, LocaleSelector } from '$comp'; import { user } from '$lib/store'; - import { _ } from 'svelte-i18n'; + import { t } from '$lib/translations'; export let howItWorks; export let faq; @@ -28,30 +28,30 @@ @@ -70,35 +70,35 @@ >
{$t('nav.howItWorks')} - + {$t('nav.about')} {#if !$user} {:else} {/if} diff --git a/src/components/LandingHero.svelte b/src/components/LandingHero.svelte index 6553d271..1415692e 100644 --- a/src/components/LandingHero.svelte +++ b/src/components/LandingHero.svelte @@ -2,7 +2,7 @@ import { goto } from '$app/navigation'; import { Icon, Image } from '$comp'; import { user } from '$lib/store'; - import { _ } from 'svelte-i18n'; + import { t } from '$lib/translations';
@@ -10,17 +10,17 @@

- {$_('landing.header_before_icon')} + {$t('landing.header_before_icon')} - {$_('landing.header_with_icon')} + {$t('landing.header_with_icon')} - {$_('landing.header_after_icon')} + {$t('landing.header_after_icon')}

- {$_('landing.subheader')} + {$t('landing.subheader')}

{#if !$user}
@@ -28,7 +28,7 @@ class="bg-black text-white border rounded-full px-6 py-2 font-bold" on:click={() => goto('/register')} > - {$_('nav.startInSeconds')} + {$t('nav.startInSeconds')}
{/if} diff --git a/src/components/LocaleSelector.svelte b/src/components/LocaleSelector.svelte index 2ae65986..4672a564 100644 --- a/src/components/LocaleSelector.svelte +++ b/src/components/LocaleSelector.svelte @@ -1,5 +1,5 @@ diff --git a/src/components/RegisterOrLogin.svelte b/src/components/RegisterOrLogin.svelte index acf98523..2d1ee6a5 100644 --- a/src/components/RegisterOrLogin.svelte +++ b/src/components/RegisterOrLogin.svelte @@ -4,7 +4,7 @@ import { user, token } from '$lib/store'; import { auth } from '$lib/socket'; import { goto } from '$app/navigation'; - import { _ } from 'svelte-i18n'; + import { t } from '$lib/translations'; export let pageID; @@ -30,11 +30,11 @@
-

{$_('login.' + pageID)}

+

{$t('login.' + pageID)}

- +
- + {#if revealPassword} - {$_('login.passwordRecommendation')} + {$t('login.passwordRecommendation')}

{:else}
{$_('login.forgotPassword')}{$t('login.forgotPassword')}
{/if}

- {pageID === 'register' ? $_('login.haveAccount') : $_('login.noAccount')} + {pageID === 'register' ? $t('login.haveAccount') : $t('login.noAccount')} - {pageID === 'register' ? $_('login.signIn') : $_('login.register')} + {pageID === 'register' ? $t('login.signIn') : $t('login.register')}

diff --git a/src/lib/i18n.js b/src/lib/i18n.js deleted file mode 100644 index 3105c709..00000000 --- a/src/lib/i18n.js +++ /dev/null @@ -1,48 +0,0 @@ -import { register, init, getLocaleFromNavigator } from 'svelte-i18n'; - -// The list of locales to look for -// ADD ALL NEW LANGUAGE CODES TO THIS LIST -const localeCodes = ['en', 'fr']; - -// the default locale to use if none was found -const defaultLocale = 'en'; - -// Adds a new locale based on its code -function addLocale(localeCode) { - register(localeCode, () => import(`../locales/${localeCode}.json`)); -} - -// Picks the default locale based on navigator locale and the list of available locales -function pickLocale(navigatorLocale, availableLocales) { - // locale can be null the first time you load this - // return the default locale in that case - reloading should fix this - if (!navigatorLocale) return defaultLocale; - - // determine langugage part of locale - // (e.g. if navigatorLocale is 'en-US', languageCode is 'en') - let dashIndex = navigatorLocale ? navigatorLocale.indexOf('-') : -1; - let languageCode; // navigator locale without the regional part - if (dashIndex === -1) { - languageCode = navigatorLocale; - } else { - languageCode = navigatorLocale.slice(0, dashIndex); - } - - // get locale - if (availableLocales.includes(navigatorLocale)) { - return navigatorLocale; - } else if (availableLocales.includes(languageCode)) { - return languageCode; - } else { - return navigatorLocale; - } -} - -// add locales -localeCodes.forEach(addLocale); - -let initialLocale = pickLocale(getLocaleFromNavigator(), localeCodes); -init({ - fallbackLocale: defaultLocale, - initialLocale: initialLocale -}); diff --git a/src/lib/translations/index.js b/src/lib/translations/index.js new file mode 100644 index 00000000..2bc5477e --- /dev/null +++ b/src/lib/translations/index.js @@ -0,0 +1,9 @@ +import i18n from 'sveltekit-i18n'; +import translations from './translations'; + +const config = { + initLocale: 'en', + translations, +}; + +export const { t, l, locales, locale } = new i18n(config); diff --git a/src/lib/translations/lang.json b/src/lib/translations/lang.json new file mode 100644 index 00000000..28d8fb36 --- /dev/null +++ b/src/lib/translations/lang.json @@ -0,0 +1,4 @@ +{ + "en": "English", + "fr": "French" +} diff --git a/src/lib/translations/translations.js b/src/lib/translations/translations.js new file mode 100644 index 00000000..5066b818 --- /dev/null +++ b/src/lib/translations/translations.js @@ -0,0 +1,225 @@ +import lang from './lang.json'; + +export default { + en: { + 404: { + 404: '404', + pageNotFound: 'Page not found.' + }, + about: { + header: 'About', + p1: 'CoinOS is an open source bitcoin web wallet, point of sale, ecommerce marketplace and exchange platform. Development started in Vancouver in September 2012 as a way to provide local merchants with a convenient way to accept bitcoin payments.', + p2: 'The feature set has grown over the years to accomodate a wide variety of use cases with the goal of making it as easy as possible for anyone to get started using bitcoin quickly, cheaply, and securely.', + p3: "Anyone can download the source code and host their own instance of the platform backed by their own bitcoin, liquid or lightning nodes, or reach out and we'll gladly set this up for you.", + p4: 'Intra-account transfers between custodial wallets of different users on our server are completely free, instant, and unlimited.', + founder: { + header: 'The Founder', + name: 'Adam Soltys', + position: 'Chief Technical Officer', + qualifications: [ + 'Running bitcoin since 2011', + '20+ years web development experience in government and industry', + 'Early bitcoin Vancouver meetup organizer', + 'Founder of The bitcoin Co-op and early supporter of Decentral Vancouver', + 'Yogi, permaculturist, anarchist, decentralist', + 'Husband, father, brother, son' + ] + } + }, + error: { + header: 'Error', + message: 'Please try again or contact support.', + signIn: 'Please sign in to continue.' + }, + faq: { + header: 'FAQ', + cost: { + question: 'What does it cost?', + answer: + 'CoinOS is free to use. You only pay a 1% fee if/when you withdraw your funds. Compare this to 3% typically charged by a credit card processor.' + }, + compatibility: { + question: 'Do I need any special device or software?', + answer: + 'No. CoinOS is web-based, so as long as you have an internet connection, you can use it on any device or hardware. Most merchants might use it on a phone or a tablet.' + }, + safety: { + question: 'Are my funds safe?', + answer: + 'Your funds are stored on our secure server, however we recommend that you withdraw them to your own cold storage for long-term savings.' + } + }, + footer: { + followUs: 'Follow Us', + twitter: 'Twitter', + github: 'GitHub', + company: 'Company', + telegram: 'Telegram', + support: 'Support', + jobs: 'Jobs' + }, + howItWorks: { + header: 'How It Works', + step1: { + header: '1. Create your account', + description: 'A username & password is all you need to get started.' + }, + step2: { + header: '2. Ask for payments', + description: 'The same as you normally would, but with bitcoin.' + }, + step3: { + header: "3. That's all!", + description: 'You can convert to local currency at any point.' + } + }, + invoice: { + addTip: 'Add a tip', + addTipq: 'Add a tip?', + done: 'Done', + paymentSuccessful: 'Payment Successful!' + }, + jobs: { + header: 'Jobs', + subheader: 'Current Openings', + pitch1: + 'CoinOS is actively looking for developers to join our growing team (full-time or part-time, remote working OK).', + pitch2: + 'Excited about working on open source bitcoin? Then take a look at our repositories on', + github: 'GitHub', + pitch3: + "If you think you can make an impact, we'd love to hear from you. Send us your resume to" + }, + landing: { + header_before_icon: 'The', + header_with_icon: 'easiest', + header_after_icon: 'way to accept bitcoin in your store.', + subheader: + 'Grow your customer base and revenue by accepting bitcoin with an easy-to-use and managed Point of Sale. No software or hardware required.', + info1: { + title: 'Instant payments via Lightning', + description: + 'The moment your customer sends a payment, it’s there. No waiting for bank settlements or worrying about chargebacks. Instant settlement, in seconds. Say goodbye to 3% credit card processing fees.' + }, + info2: { + title: 'Simple to use, custodial by default', + description1: 'Just enter an amount, share QR code and you’re done.', + description2: + 'CoinOS is custodial by default, which eliminates the need to understand how bitcoin/lightning works. We do all the heavy lifting so you can focus on your business.', + description3: + 'You always have the option of taking custody of your own keys.' + }, + info3: { + title: 'Brand it your way!', + description: + 'Customize your point of sale look and feel, or keep it on default - totally up to you.' + } + }, + login: { + username: 'Username', + password: 'Password', + passwordRecommendation: + 'We recommend a long, random password generated with a password manager.', + forgotPassword: 'Forgot Password?', + haveAccount: 'Already have an account?', + noAccount: "Don't have an account?", + register: 'Register', + signIn: 'Sign In', + failed: 'Login failed' + }, + nav: { + startInSeconds: 'Start in Seconds', + account: 'Account', + signIn: 'Sign In', + signOut: 'Sign Out', + dashboard: 'Dashboard', + settings: 'Settings', + support: 'Support' + }, + user: { + addressGoesHere: 'Address goes here', + follow: 'Follow', + remove: 'Remove', + scanToPayBTC: 'Scan to pay with bitcoin', + dashboard: { + ACCOUNT_BALANCE: 'ACCOUNT BALANCE', + bitcoinPrice: 'Bitcoin Price:', + conversionFeeWarning: + 'You will be charged a 1% conversion fee if you withdraw more of a certain type of Bitcoin than you deposit.', + dataFromBinance: 'Data from Binance.', + fetchingRate: 'fetching rate...', + optionalNote: 'Note (Optional)', + send: 'Send', + withdraw: 'Withdraw' + }, + receive: { + lessThan1BTCWarning: 'Please enter an amount less than 1 bitcoin.', + showQR: 'Show QR' + }, + settings: { + header: 'Settings', + ACCOUNT: 'ACCOUNT', + POINT_OF_SALE: 'POINT OF SALE', + SECURITY: 'SECURITY', + locale: 'Language', + username: 'Username', + newPassword: 'New Password', + businessAddress: 'Business Address', + emailNotifications: 'Email Notifications', + emailNotificationsDescription: + 'Get notified via email when a change occurs on your account or when people send you payments.', + smsNotifications: 'SMS Notifications', + smsNotificationsDescription: + 'CoinOS will send you text notifications when this is enabled.', + theme: 'Color Theme', + themeDescription: 'Select from the default color themes.', + localCurrency: 'Local Currency', + btcUnit: 'Display bitcoin in:', + bitcoin: 'Bitcoin', + satoshis: 'Satoshis', + securityPIN: 'Security PIN', + securityPINDescription: + 'Set a security pin that will be used to unlock your settings and to send outgoing payments.', + setPIN: 'Set PIN', + autoLock: 'Auto-Lock Timer', + autoLockDescription: + 'Your account will go into a secure mode automatically after a specified time:', + twofa: '2-Factor Authentication', + twofaDescription: + 'Add an extra level of security to your device by enableing 2-factor authentication.', + twofaSetup: 'Set up 2FA' + }, + support: { + header: 'Support', + email: 'Email', + accountName: 'Account Name', + message: 'Message', + send: 'Send' + }, + transactions: { + header: 'Transaction History', + AMOUNT: 'AMOUNT', + TYPE: 'TYPE', + TIME: 'TIME', + sent: 'Sent', + received: 'Received', + empty: 'No transactions yet.' + } + } + }, + fr: { + about: { + header: 'À Propos' + }, + faq: { + header: 'FAQ' + }, + howItWorks: { + header: 'Comment Elle Fonctionne' + }, + nav: { + startInSeconds: 'Commence en Secondes', + signIn: 'Connexion' + } + } +}; diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte index 2bacc8a6..d3b9306d 100644 --- a/src/routes/+error.svelte +++ b/src/routes/+error.svelte @@ -1,7 +1,7 @@ {#if $page.error.message.includes('not found') || $page.status === 404} @@ -15,9 +15,9 @@ -

{($_('error.header'), { default: 'Error' })}

+

{($t('error.header'), { default: 'Error' })}

{$page.error.message.toUpperCase()}

-

{($_('error.message'), { default: 'Please try again or contact support.' })}

+

{($t('error.message'), { default: 'Please try again or contact support.' })}

{/if} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 1de48b9e..dfe52894 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,7 +1,5 @@ -{#if ready && !$isLoading} +{#if ready} {:else} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index bb5df050..cb49dbe4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -10,7 +10,7 @@ Footer } from '$comp'; - import { _ } from 'svelte-i18n'; + import { t } from '$lib/translations'; let howItWorks; let faq; @@ -34,32 +34,32 @@ - - {$_('landing.info2.description1')} + + {$t('landing.info2.description1')}

- {$_('landing.info2.description2')} + {$t('landing.info2.description2')}

- {@html $_('landing.info2.description3')} + {@html $t('landing.info2.description3')}
-

{$_('howItWorks.header')}

+

{$t('howItWorks.header')}

@@ -73,7 +73,7 @@
-

{$_('faq.header')}

+

{$t('faq.header')}

{#each faqIDs as faqID} {/each} diff --git a/src/routes/[username]/+page.svelte b/src/routes/[username]/+page.svelte index ed428d46..f2117be2 100644 --- a/src/routes/[username]/+page.svelte +++ b/src/routes/[username]/+page.svelte @@ -4,7 +4,7 @@ import { AppHeader, Icon, PageNotFound } from '$comp'; import { user } from '$lib/store'; import { copy } from '$lib/utils'; - import { _ } from 'svelte-i18n'; + import { t } from '$lib/translations'; export let data; let lightningAddress = `${data?.username}@coinos.io`; @@ -43,7 +43,7 @@

{data.username}

-

{$_('user.addressGoesHere')}

+

{$t('user.addressGoesHere')}

@@ -62,7 +62,7 @@ class="w-[292px] md:w-[342px] h-[342px] border border-lightgrey rounded-3xl flex p-5 justify-center items-center relative" /> -

{$_('user.scanToPayBTC')}

+

{$t('user.scanToPayBTC')}

{$user.username}

- {$_('user.addressGoesHere')} + {$t('user.addressGoesHere')}
@@ -58,28 +58,28 @@ {#if !withdrawing} {$_('user.dashboard.bitcoinPrice')} + >{$t('user.dashboard.bitcoinPrice')} {$selectedRate ? btcPrice : $_('user.dashboard.fetchingRate')}{$selectedRate ? btcPrice : $t('user.dashboard.fetchingRate')} - {@html $_('user.dashboard.dataFromBinance')} + {@html $t('user.dashboard.dataFromBinance')}

- {$_('user.dashboard.ACCOUNT_BALANCE')} + {$t('user.dashboard.ACCOUNT_BALANCE')}

{$selectedRate ? accountBalanceFiat : $_('user.dashboard.fetchingRate')}{$selectedRate ? accountBalanceFiat : $t('user.dashboard.fetchingRate')} {accountBalanceSats} SAT {$t('user.dashboard.withdraw')} -

{$_('user.dashboard.conversionFeeWarning')}

+

{$t('user.dashboard.conversionFeeWarning')}

{:else}