From 1072c7a213baeace777d18b888eb43086afeb87e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 23 Aug 2022 02:26:09 -0700 Subject: generate new invoice on tip --- src/lib/utils.js | 2 + src/routes/+error.svelte | 6 +- src/routes/+layout.svelte | 2 - src/routes/[username]/receive/+page.svelte | 2 +- src/routes/invoice/+server.js | 24 +++---- src/routes/invoice/[id]/+page.server.js | 14 ++-- src/routes/invoice/[id]/+page.svelte | 103 +++++++++++++++++++---------- 7 files changed, 91 insertions(+), 62 deletions(-) diff --git a/src/lib/utils.js b/src/lib/utils.js index a1bdf8d7..65025c3a 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -47,6 +47,8 @@ export const put = (url, body, headers) => { method: 'PUT', body: JSON.stringify(body), headers + }).then(async (r) => { + if (!r.ok) throw new Error('put failed'); }); }; diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte index d3b9306d..58a3144d 100644 --- a/src/routes/+error.svelte +++ b/src/routes/+error.svelte @@ -15,9 +15,9 @@ -

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

-

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

-

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

+

{$t('error.header')}

+

{$page.error.message}

+

{$t('error.message')}

{/if} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 185eb140..0485e71d 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -24,8 +24,6 @@ goto('/login'); warning($t('error.signIn')); } - } else { - ready = true; } connect(); diff --git a/src/routes/[username]/receive/+page.svelte b/src/routes/[username]/receive/+page.svelte index 181f8ea6..c588bbe0 100644 --- a/src/routes/[username]/receive/+page.svelte +++ b/src/routes/[username]/receive/+page.svelte @@ -81,7 +81,7 @@ }; let submit = async () => { - let { id } = await post('/invoice', { + let id = await post('/invoice', { amount, rate: $selectedRate, username: $page.params.username diff --git a/src/routes/invoice/+server.js b/src/routes/invoice/+server.js index c77784d7..4b961be9 100644 --- a/src/routes/invoice/+server.js +++ b/src/routes/invoice/+server.js @@ -1,16 +1,16 @@ -import { json as json$1 } from '@sveltejs/kit'; -import { post } from '$lib/utils'; -import { user } from '$lib/store'; - -let network = 'lightning'; +import cookie from 'cookie'; +import { get, post } from '$lib/utils'; export async function POST({ request }) { - let { amount, rate, username, text } = await request.json(); - if (!text) ({ text } = await post('/lightning/invoice', { amount })); - let { uuid: id } = await post('/invoice', { - invoice: { amount, currency: user.currency, network, rate, text }, - user: { username } - }); + let { token } = cookie.parse(request.headers.get('cookie') || ''); + + let network = 'lightning'; + let { amount, currency, rate, tip, text, username } = await request.json(); + let headers = { authorization: `Bearer ${token}` }; + + ({ text } = await post('/lightning/invoice', { amount }, headers)); + let invoice = { amount, currency, network, rate, tip, text }; + let { uuid } = await post('/invoice', { invoice, user: { username } }, headers); - return json$1({ id }); + return new Response(JSON.stringify(uuid), { headers: { 'content-type': 'application/json' } }); } diff --git a/src/routes/invoice/[id]/+page.server.js b/src/routes/invoice/[id]/+page.server.js index 78607545..d46d039b 100644 --- a/src/routes/invoice/[id]/+page.server.js +++ b/src/routes/invoice/[id]/+page.server.js @@ -1,14 +1,8 @@ -import { get } from '$lib/utils'; +import cookie from 'cookie'; +import { get, post } from '$lib/utils'; export async function load({ params }) { let { id } = params; - let { - amount, - rate, - status, - text, - user: { username } - } = await get(`/invoice?uuid=${id}`); - - return { amount, id, rate, username, status, text }; + return { id, invoice: await get(`/invoice?uuid=${id}`) }; } + diff --git a/src/routes/invoice/[id]/+page.svelte b/src/routes/invoice/[id]/+page.svelte index 19809f9f..e8bd9edf 100644 --- a/src/routes/invoice/[id]/+page.svelte +++ b/src/routes/invoice/[id]/+page.svelte @@ -3,54 +3,85 @@ import { browser } from '$app/env'; import { invoices, user } from '$lib/store'; import { Icon, Image } from '$comp'; - import { goto } from '$app/navigation'; - import { onMount } from 'svelte'; + import { goto, invalidate } from '$app/navigation'; + import { onMount, tick } from 'svelte'; import { copy } from '$lib/utils'; import { t } from '$lib/translations'; export let data; - $: ({ amount, id, rate, status, text, username } = data); - $invoices[id] = { amount, id, rate, status, text, username }; + $: refresh(data); + let { invoice, id } = data; + let { + amount, + rate, + status, + text, + tip, + user: { username, currency } + } = invoice; + + amount -= tip; + + let refresh = (data) => { + ({ invoice, id } = data); + ({ + amount, + rate, + status, + text, + tip, + user: { username, currency } + } = invoice); + + amount -= tip; + + tipPercent = Math.round((tip / amount) * 100); + }; + + $invoices[id] = { amount, id, rate, status, text, tip, username }; $: amountFiat = parseFloat(((amount * rate) / 100000000).toFixed(2)); let tipPercent = 0; let qr; - $: tipAmount = customTipAmount - ? customTipAmount < 0 - ? (customTipAmount = 0) - : customTipAmount - : (amountFiat / 100) * tipPercent; + $: tipAmount = (amountFiat / 100) * tipPercent; $: tipAmountFormatted = new Intl.NumberFormat('en-US', { style: 'currency', - currency: $user.currency + currency }).format(tipAmount); - $: tipAmountSats = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format( - tipAmount / (rate / 100000000) - ); + $: tipAmountSats = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(tip); $: totalAmountSats = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format( amount + parseFloat(tipAmountSats.replace(/,/g, '')) ); - $: update(tipAmountSats); - let update = async (n) => { - let { id } = await post('/invoice', { - amount: amount + reverseFormat(n), + let apply = async () => { + tipAmount = customTipAmount; + tipPercent = Math.round((tipAmount / amountFiat) * 100); + update(); + }; + + let update = async () => { + await tick(); + tip = (tipAmount * 100000000) / rate; + let r = await post(`/invoice`, { + amount: amount + tip, rate, + tip, text, username }); - ({ text } = await get(`/invoice/${id}`)); + + goto(`/invoice/${r}`); }; $: totalAmountFormatted = new Intl.NumberFormat('en-US', { style: 'currency', - currency: $user.currency + currency }).format(amountFiat + parseFloat(tipAmount)); const amountFormatted = new Intl.NumberFormat('en-US', { @@ -59,13 +90,22 @@ $: invoiceAmountFiatFormatted = new Intl.NumberFormat('en-US', { style: 'currency', - currency: $user.currency + currency }).format(amountFiat); let customTipAmount; const tipAmounts = ['None', '10%', '15%', '20%']; + let timeout; + const handleSlide = (e) => { + customTipAmount = ''; + customInput.value = ''; + tipPercent = e.target.value; + clearTimeout(timeout); + timeout = setTimeout(update, 100); + }; + const handleTipButtonClick = (amount) => { customTipAmount = ''; customInput.value = ''; @@ -75,6 +115,8 @@ } else { tipPercent = amount.slice(0, 2); } + + update(); }; const handleCustomTipAmount = (e) => { @@ -83,8 +125,8 @@ }; $: generate(text); - let generate = async (ready) => { - if (!ready) return; + let generate = async (text) => { + if (!(browser && text)) return; let { default: QRCodeStyling } = await import('qr-code-styling'); const qrCode = new QRCodeStyling({ @@ -103,6 +145,7 @@ } }); + while (qr.firstChild) qr.removeChild(qr.lastChild); qrCode.append(qr); }; @@ -116,18 +159,14 @@ tipAmount = 0; showMobileTip = false; } else { - goto(`/${$user.username}/receive`); + goto(`/${username}/receive`); } }; let customInput; const handleDoneClick = () => { - if ($user) { - goto(`/${$user.username}/receive`); - } else { - goto('/'); - } + goto(`/${username}/receive`); }; @@ -167,11 +206,7 @@ max="100" value={tipPercent} class="px-2" - on:input={(e) => { - customTipAmount = ''; - customInput.value = ''; - tipPercent = e.target.value; - }} + on:input={handleSlide} />
@@ -210,7 +245,7 @@ ? 'opacity-50' : 'opacity-100'}" disabled={showMobileTip ? !customTipAmount && !tipAmount : !customTipAmount} - on:click={() => (showMobileTip = false)}>DoneApply
-- cgit v1.2.3 From 5de2a508609f84af1b94f53b098b05092599150c Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 10:43:30 -0500 Subject: fixed broken translations & use json locales instead of JS --- src/components/About.svelte | 11 +- src/lib/translations/index.js | 23 +++- src/lib/translations/lang.json | 2 +- src/lib/translations/translations.js | 225 ----------------------------------- 4 files changed, 30 insertions(+), 231 deletions(-) delete mode 100644 src/lib/translations/translations.js diff --git a/src/components/About.svelte b/src/components/About.svelte index 794a5107..3cd25f8c 100644 --- a/src/components/About.svelte +++ b/src/components/About.svelte @@ -54,9 +54,14 @@ -
    +
      +
    • {$t('about.founder.qualifications.bitcoin')}
    • +
    • {$t('about.founder.qualifications.webDev')}
    • +
    • {$t('about.founder.qualifications.bitcoinVancouver')}
    • +
    • {$t('about.founder.qualifications.bitcoinCoop')}
    • +
    • {$t('about.founder.qualifications.beliefs')}
    • +
    • {$t('about.founder.qualifications.familialRelationships')}
    • +
    diff --git a/src/lib/translations/index.js b/src/lib/translations/index.js index 023da884..6ed83689 100644 --- a/src/lib/translations/index.js +++ b/src/lib/translations/index.js @@ -1,9 +1,28 @@ import i18n from 'sveltekit-i18n'; -import translations from './translations'; +import lang from './lang.json'; const config = { initLocale: 'en', - translations + translations: { + en: { lang }, + fr: { lang } + }, + loaders: [ + { + locale: 'en', + key: '', + loader: async () => ( + await import("../../locales/en.json") + ).default + }, + { + locale: 'fr', + key: '', + loader: async () => ( + await import("../../locales/fr.json") + ).default + } + ] }; export const { t, l, locales, locale } = new i18n(config); diff --git a/src/lib/translations/lang.json b/src/lib/translations/lang.json index 6cf55908..b01c522b 100644 --- a/src/lib/translations/lang.json +++ b/src/lib/translations/lang.json @@ -1,4 +1,4 @@ { "en": "English", - "fr": "French" + "fr": "Français" } diff --git a/src/lib/translations/translations.js b/src/lib/translations/translations.js deleted file mode 100644 index 5066b818..00000000 --- a/src/lib/translations/translations.js +++ /dev/null @@ -1,225 +0,0 @@ -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' - } - } -}; -- cgit v1.2.3 From 21910fd069b40aa1c63d9ce0651d98a7effc555b Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 11:14:54 -0500 Subject: locale selector uses proper language names & added fallback locale --- src/components/LocaleSelector.svelte | 4 ++-- src/lib/translations/index.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/LocaleSelector.svelte b/src/components/LocaleSelector.svelte index ec5bc781..e1888e9f 100644 --- a/src/components/LocaleSelector.svelte +++ b/src/components/LocaleSelector.svelte @@ -1,10 +1,10 @@ diff --git a/src/lib/translations/index.js b/src/lib/translations/index.js index 6ed83689..c8a0a588 100644 --- a/src/lib/translations/index.js +++ b/src/lib/translations/index.js @@ -3,6 +3,7 @@ import lang from './lang.json'; const config = { initLocale: 'en', + fallbackLocale: 'en', translations: { en: { lang }, fr: { lang } -- cgit v1.2.3 From 29129260d8574cfa8deec32cae324e21816f9ecc Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 11:23:20 -0500 Subject: Loaders & translations now generated from lang.json data --- src/lib/translations/index.js | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/lib/translations/index.js b/src/lib/translations/index.js index c8a0a588..dc03c0b6 100644 --- a/src/lib/translations/index.js +++ b/src/lib/translations/index.js @@ -1,13 +1,28 @@ import i18n from 'sveltekit-i18n'; import lang from './lang.json'; +// setup loaders & translations from lang.json data +function createLocaleLoader(localeCode) { + return { + locale: localeCode, + key: '', + loader: async () => ( + await import(`../../locales/${localeCode}.json`) + ).default + }; +} + +const availableLocales = Object.keys(lang); +const translations = {}; +for (let i = 0; i < availableLocales.length; i++) { + translations[availableLocales[i]] = { lang }; +} +const loaders = availableLocales.map(createLocaleLoader); + const config = { initLocale: 'en', fallbackLocale: 'en', - translations: { - en: { lang }, - fr: { lang } - }, + translations: translations, loaders: [ { locale: 'en', -- cgit v1.2.3 From cbdd2672ab52a9a7bcb2a2696d5519815b9cd0fb Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 11:43:11 -0500 Subject: put sveltekit-i18n locale in localStorage --- src/routes/+layout.svelte | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 0485e71d..5eab20bd 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -9,7 +9,9 @@ import { goto } from '$app/navigation'; import { LoadingSplash } from '$comp'; import { warning, protectedRoutes } from '$lib/utils'; - import { t } from '$lib/translations'; + import { t, locale } from '$lib/translations'; + + const localeLocalStorageKey = 'sveltekit-i18n-locale'; $: $token = data.token; @@ -19,6 +21,13 @@ $: $selectedRate = data.user && $rate * (data.rates[data.user.currency] / data.rates.USD); onMount(() => { + let localStorageLocale = localStorage.getItem(localeLocalStorageKey); + if (localStorageLocale) locale.set(localStorageLocale); + + locale.subscribe((lng) => { + if (lng) localStorage.setItem(localeLocalStorageKey, lng); + }); + if (protectedRoutes.find((p) => $page.url.pathname.match(p))) { if (!$token) { goto('/login'); -- cgit v1.2.3 From 36f3d21efedb03203fe41698f6d54ddaec5093e7 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 13:32:33 -0500 Subject: removed langname from locale files --- src/locales/en.json | 1 - src/locales/fr.json | 1 - 2 files changed, 2 deletions(-) diff --git a/src/locales/en.json b/src/locales/en.json index 1d3446c9..df7c8b0f 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1,5 +1,4 @@ { - "langname": "English", "404": { "404": "404", "pageNotFound": "Page not found." diff --git a/src/locales/fr.json b/src/locales/fr.json index acc0eda7..231a71db 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1,5 +1,4 @@ { - "langname": "Français", "about": { "header": "À Propos" }, -- cgit v1.2.3 From 82929040dc83ce13d058f4e81a0e8bca45173000 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 14:08:46 -0500 Subject: translation script can now create new locales & fixed bugs --- src/locales/guided_translation.py | 59 +++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/src/locales/guided_translation.py b/src/locales/guided_translation.py index e5f94cfe..65f58db2 100644 --- a/src/locales/guided_translation.py +++ b/src/locales/guided_translation.py @@ -1,8 +1,10 @@ #!/usr/bin/python -import argparse, json, logging +import argparse, json, logging, sys +from pathlib import Path DEFAULT_FROM_LOCALE = 'en' +LOCALE_DATA_FILEPATH = '../lib/translations/lang.json' def nested_dict_keys(d, _keyname_prefix=''): entry_list = [] @@ -14,6 +16,18 @@ def nested_dict_keys(d, _keyname_prefix=''): entry_list += [_keyname_prefix + key] return entry_list +def create_locale(locale_code): + logging.debug("Creating locale %s...", locale_code) + with open(LOCALE_DATA_FILEPATH, 'r', encoding='utf-8') as lang_file: + lang_data = json.load(lang_file) + + lang_data[locale_code] = input("What is the name of the language " + locale_code + "? ") + + with open(LOCALE_DATA_FILEPATH, 'w') as lang_file: + json.dump(lang_data, lang_file, ensure_ascii=False, indent='\t') + lang_file.write('\n') + logging.debug("Created locale %s.", locale_code) + def localize_string(string_id, from_data, to_data): logging.debug("Translating string with id %s", string_id) id_parts = string_id.split('.') @@ -28,6 +42,7 @@ def localize_string(string_id, from_data, to_data): print(to_translate) translated = input("Type the translated text then press ENTER: ") + print(translated) # find/create place to put translated string translation_location = to_data # the dictionary or list that should contain the translated string @@ -42,22 +57,35 @@ if __name__ == "__main__": # setup and parse commandline arguments args_parser = argparse.ArgumentParser(description="guided translation of CoinOS") args_parser.add_argument('from_locale', nargs='?', type=str, - help='which locale to translate from') + help="which locale to translate from") args_parser.add_argument('to_locale', nargs='?', type=str, - help='which locale to translate to') + help="which locale to translate to") + args_parser.add_argument('-v', '--verbose', action='count', default=0, + help="show more information") + args_parser.add_argument('-V', '--version', action='store_true', + help="show version info and exit") args = args_parser.parse_args() + if args.version: + print("Guided Translation Script version 0.2.0") + sys.exit(0) + from_locale = args.from_locale or input("Which locale do you want to translate from (default: %s)? " % DEFAULT_FROM_LOCALE) or DEFAULT_FROM_LOCALE to_locale = args.to_locale or input("Which locale do you want to translate to? ") if not to_locale: raise ValueError("You need to specify a language to translate to.") - logging.basicConfig(format='%(levelname)s: %(message)s') + if args.verbose >= 2: + logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG) + elif args.verbose >= 1: + logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) + else: + logging.basicConfig(format='%(levelname)s: %(message)s') # load locale files logging.debug("Reading file to convert from (%s.json)", from_locale) - with open(from_locale + ".json", 'r') as from_file: + with open(from_locale + ".json", 'r', encoding='utf-8') as from_file: from_json_text = from_file.read() logging.debug("Converting from data from JSON to object") from_data = json.loads(from_json_text) @@ -67,10 +95,16 @@ if __name__ == "__main__": logging.debug("List of strings: %s", from_id_list) logging.debug("Reading file to convert to (%s.json)", to_locale) - with open(to_locale + ".json", 'r') as to_file: - to_json_text = to_file.read() - logging.debug("Converting to data from JSON to object") - to_data = json.loads(to_json_text) + to_filepath = "./" + to_locale + ".json" + if Path(to_filepath).exists(): + with open(to_locale + ".json", 'r', encoding='utf-8') as to_file: + to_json_text = to_file.read() + logging.debug("Converting to data from JSON to object") + to_data = json.loads(to_json_text) + else: + logging.info("No file found. Creating new locale.") + create_locale(to_locale) + to_data = {} to_id_list = nested_dict_keys(to_data) logging.info("Successfully obtained %d strings from locale %s", len(to_id_list), to_locale) @@ -83,9 +117,10 @@ if __name__ == "__main__": localize_string(string_id, from_data, to_data) to_id_list.append(string_id) except KeyboardInterrupt: - print("Program interrupted. Saving strings and closing program...") + print("\nProgram interrupted. Saving strings...") # save localized data - with open(to_locale + ".json", 'w') as to_file: - json.dump(to_data, to_file, ensure_ascii=False, indent=2) + with open(to_locale + ".json", 'w', encoding='utf-8') as to_file: + json.dump(to_data, to_file, ensure_ascii=False, indent='\t') + to_file.write('\n') logging.info("Saved %d localized strings to %s.json", len(to_id_list), to_locale) -- cgit v1.2.3 From bd132fd1e54c07b7ff228132c03979e9594d5df1 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 14:20:26 -0500 Subject: updated technical i18n documentation for sveltekit-i18n --- doc/i18n-technical.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/doc/i18n-technical.md b/doc/i18n-technical.md index a0d64938..46fbb094 100644 --- a/doc/i18n-technical.md +++ b/doc/i18n-technical.md @@ -2,21 +2,20 @@ _NOTE: This documentation was written for people with a technical background. If you do not have a technical background, consider reading [this guide](./i18n.md) instead._ -Last Updated: 2022-08-08 +Last Updated: 2022-08-23 ## Dependencies -CoinOS's internationalization system depends on the `npm` package [`svelte-i18n`](https://www.npmjs.com/package/svelte-i18n). Consider reading [its documentation](https://github.com/kaisermann/svelte-i18n/blob/HEAD/docs/Getting%20Started.md) in addition to this. +CoinOS's internationalization system depends on the `npm` package [`sveltekit-i18n`](https://www.npmjs.com/package/sveltekit-i18n). Consider reading [its documentation](https://github.com/sveltekit-i18n/lib/tree/master/docs/README.md) in addition to this. ## Internationalization Code -The main code for CoinOS's internationalization is at `src/lib/i18n.js`. When imported, it does the following: +The main code for CoinOS's internationalization is at `src/lib/translations/index.js`. When imported, it does the following: -1. Load all of the locales [asynchronously](https://github.com/kaisermann/svelte-i18n/blob/main/docs/Getting%20Started.md#32-asynchronous). -2. Pick a locale intelligently, depending on the available locales and the navigator locale, using `pickLocale`. Specifically, if the user's locale (e.g. `en-US`) isn't available but its non-regional version (e.g. `en`) is, the system will use the non-regional locale. -3. Initialize `svelte-i18n`. +1. Load all of the locales asynchronously, based on . +3. Initialize `sveltekit-i18n`. -It also defines important constants, including the list of available locales and the default locale. This code is loaded by importing `$lib/i18n` in `src/routes/__layout.svelte`. +It also defines important constants, including the list of available locales and the default locale. This code is loaded by importing `$lib/translations` in `src/routes/+layout.svelte`. This code, which runs in the frontend, also persists the locale in `localStorage`. ## Locale Files @@ -34,14 +33,12 @@ Each locale in `coinos-ui-v2` is defined by a JSON file in `src/locales`. Its na ## Internationalizing Strings -Strings are internationalized by simply using `svelte-i18n`'s [`$format`](https://github.com/kaisermann/svelte-i18n/blob/96a5adab7560249c8881e0612454e01c09273400/docs/Formatting.md) function. A localized string looks like this: +Strings are internationalized by simply using `sveltekit-i18n`'s `$t` function. A localized string looks like this: ``` {$t('stringID')} ``` -(`$_` is a convenient alias for `$format`.) - ## The Locale Selector CoinOS also has a `LocaleSelector` component, which should be used to select locales. It is a dropdown that allows you to select & update the locale. @@ -51,4 +48,5 @@ CoinOS also has a `LocaleSelector` component, which should be used to select loc CoinOS has a Python script that helps you with the technical parts of translation. It is located at `src/locales/guided_translation.py`. It also has some utility functions: - `nested_dict_keys` - gets a list of keys of a nested dictionary in dot-separated shallow format (e.g. a.b.c) +- `create_locale` - adds a new locale to the lang.json file - `localize_string` - localizes a string interactively -- cgit v1.2.3 From 85e9a9a64018744479af3631cac71a114300b7c4 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 14:23:32 -0500 Subject: update README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c181376a..35704685 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ To get started, clone or download the repo, then: - run `pnpm run dev` every time you want to start up the UI - run `pnpm format` to format the code before committing any changes +This is a frontend for [`coinos-server`](https://github.com/coinos/coinos-server), so you will need to have that running in order for this UI to be useful. + ## Libraries This UI uses the following libraries: @@ -27,4 +29,4 @@ This UI uses the following libraries: ### Internationalization -CoinOS has a system for translation using [`svelte-i18n`](https://www.npmjs.com/package/svelte-i18n). For more information and instructions on how to translate CoinOS, click [here](./doc/i18n.md). For technical details, click [here](./doc/i18n-technical.md). +CoinOS has a system for translation using [`sveltekit-i18n`](https://www.npmjs.com/package/sveltekit-i18n). For more information and instructions on how to translate CoinOS, click [here](./doc/i18n.md). For technical details, click [here](./doc/i18n-technical.md). -- cgit v1.2.3 From 68e85acdd2e7a190e41835098793a0c9827cae39 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 14:47:45 -0500 Subject: updated i18n manual for new translation format & added more info --- doc/i18n.md | 55 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/doc/i18n.md b/doc/i18n.md index 5bbd049b..2eccc7e4 100644 --- a/doc/i18n.md +++ b/doc/i18n.md @@ -1,14 +1,16 @@ # CoinOS Internationalization -CoinOS can be translated into other languages by editing JSON files. You do not need programming knowledge to do this, or to use these instructions. Here are instructions on how to internationalize CoinOS: +CoinOS can be translated into other languages by editing [JSON](https://www.json.org/json-en.html) files. You do not need programming knowledge to do this, or to use these instructions. Here are instructions on how to translate CoinOS: _NOTE: This guide was written for people without a technical background. If you want more technical details, click [here](./i18n-technical.md)._ +Last Updated: 2022-08-23 + ## Required Background Knowledge ### Language Codes -Before you can translate CoinOS, you need to know the [ISO 639-1 code](https://en.wikipedia.org/wiki/ISO_639-1) of your language. This is a standard two-letter code that your browser uses to refer to a language (for example, English is `en`, and French is `fr`). You can also add a dash and more letters to refer to a specific region (for example, American English is `en-US`, and British English is `en-GB`). A list of all codes can be found [here](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes), and Firefox-based browsers show you the code when you are selecting your browser's language. +Before you can translate CoinOS, you need to know the [ISO 639-1 code](https://en.wikipedia.org/wiki/ISO_639-1) of your language. This is a standard two-letter code that your browser uses to refer to a language (for example, English is `en`, and Spanish is `es`). You can also add a dash and more letters to refer to a specific region (for example, American English is `en-US`, and British English is `en-GB`). A list of all codes can be found [here](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes), and Firefox-based browsers show you the code when you are selecting your browser's language. ### Locale Files @@ -28,15 +30,47 @@ Each line (other than the opening and closing braces) contains a **text name**, ### The Language List -At the top of the file `src/lib/i18n.js`, there is a list of translations that looks something like this: +There is also a JSON file that controls which languages are understood. It is at `src/lib/translations/lang.json` and looks something like this: + +```JSON +{ + "en": "English", + "fr": "Français", + "es": "Español" +} +``` + +This file simply maps each language to its name. It is used both to get a list of languages and to get the name of each language for the language selector. If a translation is not in this file, CoinOS will not be able to see it. + +### JSON Sections + +You might notice that some of the left-text in the language files don't have a string after them, instead having some `{}` curly brackets, like in this example: -```js -// The list of locales to look for -// ADD ALL NEW LANGUAGE CODES TO THIS LIST -const localeCodes = ['en', 'fr']; +```JSON +"nav": { + "startInSeconds": "Start in Seconds", + "account": "Account", + "signIn": "Sign In", + "signOut": "Sign Out", + "dashboard": "Dashboard", + "settings": "Settings", + "support": "Support" +}, ``` -In order for a translation to be recognized by the CoinOS system, you need to add it to this list. At the end of the list, before the second square bracket, add a comma, then a space, then the language code in quotation marks. +These denote sections of the JSON file, which helps keep it organized. If you're translating a string that is in a section, make sure the translated string is in the same section of the new file. If that section doesn't exist, just create it. + +### HTML Tags + +Sometimes, you will see strange text surrounded with `<>` angle brackets. Every one of these "HTML tags" will be followed by another one starting with a slash. Here's an example: + +```JSON +"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.", +``` + +These apply a certain style to the text between them. For example, the tags above will make "CoinOS" and "open source" bold, leaving the rest non-bold. + +When translating strings containing tags, don't change the tags. Do translate the text between them, and don't be afraid to move them around - just make sure they contain the same part of the sentence, and that the one without the slash is always before the one with the slash. Not all of the localizable strings support HTML tags, so you shouldn't use them if they aren't in the original string you're translating. ## Creating a New Translation @@ -50,9 +84,8 @@ Follow these steps to create a new translation. You will need a GitHub account t _NOTE: "CoinOS" is a feminine noun in languages with grammatical gender._ ![Translating in GitHub](./img/translate_github.png) 5. Scroll down and use the green button to commit the file. -6. Go to the `src` folder again, then `lib`, then `i18n.js`. -7. Use the pencil icon on the top-right to edit the file, then add your language code (**in quotation marks**) to the list. - ![Adding a new translation in GitHub](./img/add_locale_github.png) +6. Go to the `src` folder again, then `lib`, then `translations`, then `lang.json`. +7. Use the pencil icon on the top-right to edit the file, then add a new line containing your language code in quotes, followed by a colon, followed by the full name of your language in quotes. Make sure every line except the last has a comma at the end. 8. Commit your changes like you did in step 5. ## Adding to an Existing Translation -- cgit v1.2.3 From dcea0fdc5866f46ab54b6b25a08b45f6afa4d7e8 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 16:20:29 -0500 Subject: added info about guided translation script --- doc/i18n.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/i18n.md b/doc/i18n.md index 2eccc7e4..224bcb3e 100644 --- a/doc/i18n.md +++ b/doc/i18n.md @@ -4,6 +4,8 @@ CoinOS can be translated into other languages by editing [JSON](https://www.json _NOTE: This guide was written for people without a technical background. If you want more technical details, click [here](./i18n-technical.md)._ +These instructions assume you have a GitHub account and have permission to modify this repository. If you do not have permission, you will need to [make a fork](https://github.com/coinos/coinos-ui-v2/fork) using the link on the top-right, then follow these instructions to translate your fork, then make a pull request using the link below the "Code" button to apply your changes to the main repository. + Last Updated: 2022-08-23 ## Required Background Knowledge @@ -102,3 +104,11 @@ Follow these steps to add to an existing translation. You will also need a GitHu _NOTE: "CoinOS" is a feminine noun in languages with grammatical gender._ 8. Repeat steps 3-7 for every piece of text you want to translate (you should probably open `en.json` in another tab, so that your changes from step 6 aren't erased). 9. Scroll down and use the green button to commit the file. + +## The Guided Translation Script + +There is also a program that helps you translate automatically - all you have to do is input the translated text and it will do the rest for you! You need a bit of technical knowledge to use it however, specifically, you need to know: +- How to use basic [git](https://git-scm.com/) (cloning, pulling, committing, pushing) +- How to run a [Python](https://www.python.org/) script + +Clone the repository, then use the guided translation script (at `src/locales/guided_translation.py`) to update the translation files. You will need to pull before running, and commit/push your changes in order for them to be applied to CoinOS. -- cgit v1.2.3 From e83c98662283b5afb84d3ed5236f5cb65872a3cb Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 16:21:05 -0500 Subject: translated About, 404 and Error to French --- src/locales/fr.json | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/locales/fr.json b/src/locales/fr.json index 231a71db..7b9fc5bd 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1,6 +1,27 @@ { "about": { - "header": "À Propos" + "header": "À Propos", + "p1": "CoinOS est un portefeuille, point de vente, marché d'e-commerce et plateforme d'échange de bitcoin open source. Development a commencé en Vancouver le septembre de 2012 pour donner aux marchands du coin un façon pratique d'accepter des paiements en bitcoin.", + "p2": "Il a eu plus de fonctions au fil des ans pour satisfaire une grande variété de cas d'utilisation avec le but de rendre commencer utiliser bitcoin rapidement, à bas prix, et en sécurité aussi façile que possible pour n'importe qui.", + "p3": "Tout le monde peux télécharger le code source et héberger leur propre instance de la plateforme soutenu par leur propres nœuds de bitcoin, liquid ou lightning, ou contactez-nous et nous l'installalons pour vous avec plaisir.", + "p4": "Transferts entre comptes de garde d'utilisateurs différents en notre serveur sont complètement gratuits, instants et sans limites.", + "founder": { + "header": "Le Fondateur", + "name": "Adam Soltys", + "position": "Officier Technique Principal", + "qualifications": { + "bitcoin": "Utilisant bitcoin depuis 2011", + "webDev": "20+ ans d'experience de programmation web en gouvernement et industrie", + "bitcoinVancouver": "Organisateur précoce de la rencontre bitcoin Vancouver", + "bitcoinCoop": "Fondateur de The Bitcoin Co-op et défenseur précoce de Decentral Vancouver", + "beliefs": "Yogi, permaculturiste, anarchiste, décentraliste", + "familialRelationships": "Mari, papa, frère, fils" + } + }, + "locations": { + "header": "Établissements", + "description": "Il y a des entreprises qui acceptent bitcoin utilisant le point de vente CoinOS. Si vous utilisez notre appli, s'il vous plait fais-le-nous savoir!" + } }, "faq": { "header": "FAQ" @@ -11,5 +32,13 @@ "nav": { "startInSeconds": "Commence en Secondes", "signIn": "Connexion" + }, + "404": { + "404": "404", + "pageNotFound": "Page non trouvée." + }, + "error": { + "header": "Erreur", + "message": "S'il vous plait réessayez ou contactez l'assistance." } } -- cgit v1.2.3 From f9c9d3105963ea0f9a7095d25e43372cc689a039 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 16:50:01 -0500 Subject: translated most of the front page to French --- src/locales/fr.json | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/locales/fr.json b/src/locales/fr.json index 7b9fc5bd..08b7bd29 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -29,9 +29,34 @@ "howItWorks": { "header": "Comment Elle Fonctionne" }, + "landing": { + "header_before_icon": "Le", + "header_with_icon": "façon", + "header_after_icon": "le plus façile d'accepter bitcoin en votre magasin.", + "subheader": "Aggrandir votre clientèle et chiffre d'affaires par accepter bitcoin avec un point de vente façile à utiliser et dirigé. Logiciel et matériel informatique non obligatoire.", + "info1": { + "title": "Paiements instants avec Lightning", + "description": "Le moment que votre client envoie un paiment, c'est la. Vous ne devez pas attendre pour les décisions de banques ou vous inquieter pour des rejets de débit. Décisions instant, en secondes. Dis au revoir aux frais de dossir 3% des cartes de crédit." + }, + "info2": { + "title": "Simple à utiliser, en garde par défaut", + "description1": "Juste entrer une quantité, partager le code QR et c'est tout!", + "description2": "Tes contes sont en garde par défaut, qui élimine le nécessité de comprendre comment bitcoin/lightning fonctionnent. Nous réalisons le plus gros du travail pour que vous pouvez vous concentrer sur votre entreprise.", + "description3": "Vous toujours avez l'option de prendre garde de vos clés." + }, + "info3": { + "title": "Personalise-le comment vous voulez", + "description": "Personalisez votre point de vente, ou rettenez-le au défaut - c'est votre chois." + } + }, "nav": { "startInSeconds": "Commence en Secondes", - "signIn": "Connexion" + "account": "Conte", + "signIn": "Connexion", + "signOut": "Déconnexion", + "dashboard": "Tableau de bord", + "settings": "Préférences", + "support": "Assistance" }, "404": { "404": "404", -- cgit v1.2.3 From 23b681cf5187ec669591413a3b74151161168b61 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 23 Aug 2022 16:55:30 -0500 Subject: small correction to french translation --- src/locales/fr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/fr.json b/src/locales/fr.json index 08b7bd29..1ef7c6e9 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -15,7 +15,7 @@ "bitcoinVancouver": "Organisateur précoce de la rencontre bitcoin Vancouver", "bitcoinCoop": "Fondateur de The Bitcoin Co-op et défenseur précoce de Decentral Vancouver", "beliefs": "Yogi, permaculturiste, anarchiste, décentraliste", - "familialRelationships": "Mari, papa, frère, fils" + "familialRelationships": "Mari, père, frère, fils" } }, "locations": { @@ -48,7 +48,7 @@ "title": "Personalise-le comment vous voulez", "description": "Personalisez votre point de vente, ou rettenez-le au défaut - c'est votre chois." } - }, + }, "nav": { "startInSeconds": "Commence en Secondes", "account": "Conte", -- cgit v1.2.3 From 44f79d7a957a8df4d0d289a6f49f4c878a1c225f Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Wed, 24 Aug 2022 15:31:43 -0500 Subject: translated the rest of the front page to French --- src/locales/fr.json | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/locales/fr.json b/src/locales/fr.json index 1ef7c6e9..f5a67f36 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -24,10 +24,44 @@ } }, "faq": { - "header": "FAQ" + "header": "FAQ", + "cost": { + "question": "Qu'est-ce que c'est le coût?", + "answer": "CoinOS est gratuit à utiliser. Vous seulment payez un prix 1% quand vous convertez vos fonds entre Bitcoin, Liquid et Lightning. Comparez-ça à les frais de dossir typiques 3% des cartes credit." + }, + "compatibility": { + "question": "Est-ce que j'ai besoin du logiciel ou appareil special?", + "answer": "Non. CoinOS est un site Web, alors vous pouvez l'utiliser sur n'importe quelle appareil tant que vous aves un connexion d'Internet. La plupart des marchands l'utilise sur un téléphone ou une tablette." + }, + "safety": { + "question": "Sont mes fonds saufs?", + "answer": "Vos fonds sont entreposés en notre serveur sécurisé, mais nous recommendons que vous les retirez à votre propre entreposage pour les sauvegarder à long terme." + } + }, + "footer": { + "followUs": "Suivez-Nous", + "twitter": "Twitter", + "github": "GitHub", + "company": "Entreprise", + "telegram": "Telegram", + "support": "Assistance", + "jobs": "Jobs" }, "howItWorks": { - "header": "Comment Elle Fonctionne" + "header": "Comment Elle Fonctionne", + "step1": { + "header": "1. Crée votre compte", + "description": "Un nom d'utilateur et mot de passe est tout qui est besoin pour commencer." + }, + "step2": { + "header": "2. Demande pour des paiements", + "description": "Comme vous faisiez normalement, mais avec bitcoin." + }, + "step3": { + "header": "3. C'est tout!", + "description": "Vous pouvez convertir au monnaie local n'importe quand." + } + }, "landing": { "header_before_icon": "Le", -- cgit v1.2.3 From a164022fe03404fff0ae9153dba892adb6d3bef8 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Wed, 24 Aug 2022 15:49:46 -0500 Subject: translated login, invoice and jobs pages to French --- src/locales/fr.json | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/locales/fr.json b/src/locales/fr.json index f5a67f36..1d279513 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1,4 +1,8 @@ { + "404": { + "404": "404", + "pageNotFound": "Page non trouvée." + }, "about": { "header": "À Propos", "p1": "CoinOS est un portefeuille, point de vente, marché d'e-commerce et plateforme d'échange de bitcoin open source. Development a commencé en Vancouver le septembre de 2012 pour donner aux marchands du coin un façon pratique d'accepter des paiements en bitcoin.", @@ -23,6 +27,11 @@ "description": "Il y a des entreprises qui acceptent bitcoin utilisant le point de vente CoinOS. Si vous utilisez notre appli, s'il vous plait fais-le-nous savoir!" } }, + "error": { + "header": "Erreur", + "message": "S'il vous plait réessayez ou contactez l'assistance.", + "signIn": "Vous devez connecter pour continuer." + }, "faq": { "header": "FAQ", "cost": { @@ -61,7 +70,6 @@ "header": "3. C'est tout!", "description": "Vous pouvez convertir au monnaie local n'importe quand." } - }, "landing": { "header_before_icon": "Le", @@ -83,6 +91,17 @@ "description": "Personalisez votre point de vente, ou rettenez-le au défaut - c'est votre chois." } }, + "login": { + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "passwordRecommendation": "Nous recommendons un mot de passe long et au hazard, généré par un gestionnaire de mots de passe.", + "forgotPassword": "Oublié ton mot de passe?", + "haveAccount": "Avez-vous déjà une conte?", + "noAccount": "N'avez-vous pas un conte?", + "register": "Enregistrer", + "signIn": "Connexion", + "failed": "Connexion failli" + }, "nav": { "startInSeconds": "Commence en Secondes", "account": "Conte", @@ -92,12 +111,18 @@ "settings": "Préférences", "support": "Assistance" }, - "404": { - "404": "404", - "pageNotFound": "Page non trouvée." + "invoice": { + "addTip": "Ajoutez un pourboire", + "addTipq": "Ajouter un pourboire?", + "done": "Fini", + "paymentSuccessful": "Paiement réussi!" }, - "error": { - "header": "Erreur", - "message": "S'il vous plait réessayez ou contactez l'assistance." + "jobs": { + "header": "Emplois", + "subheader": "Postes disponibles actuels", + "pitch1": "CoinOS recherche pour des développeurs pour joindre notre équipe croissant (temps plein ou partiel, télétravail OK)", + "pitch2": "Avez-vous hâte de travailler sur bitcoin open source? Regardez sur nos dépôts sur", + "github": "GitHub", + "pitch3": "Si vous pensez que vous pouvez exercer une influence positive, nous voulons que vous contribuez. Envoyer votre CV à" } } -- cgit v1.2.3 From 5cbe3e13bc4ed111199a5dbf619717ff0dbfd5f3 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Wed, 24 Aug 2022 16:01:25 -0500 Subject: added extra info on JSON sections --- doc/i18n.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doc/i18n.md b/doc/i18n.md index 224bcb3e..7c180dcb 100644 --- a/doc/i18n.md +++ b/doc/i18n.md @@ -62,6 +62,26 @@ You might notice that some of the left-text in the language files don't have a s These denote sections of the JSON file, which helps keep it organized. If you're translating a string that is in a section, make sure the translated string is in the same section of the new file. If that section doesn't exist, just create it. +In the translation files, sections roughly correspond to where the the strings are on CoinOS. This can be useful if you need context for a string. Here are some of these associations (`A.B` means section `B` is located inside `A`): + +| Section | Location | +|-------------------|---------------------------------------------------| +| 404 | the 404 page | +| about | the 'About' section at the bottom of the homepage | +| error | the error page | +| faq | the FAQ on the homepage | +| footer | the bottom of the homepage | +| howItWorks | the 'How it Works' section | +| invoice | the Invoice page | +| jobs | the Jobs page | +| landing | the top of the homepage | +| login | the Register and Login pages | +| user | the user page | +| user.dashboard | the user's dashboard | +| user.settings | the settings page | +| user.support | the user's support page | +| user.transactions | the user's transaction history page | + ### HTML Tags Sometimes, you will see strange text surrounded with `<>` angle brackets. Every one of these "HTML tags" will be followed by another one starting with a slash. Here's an example: @@ -111,4 +131,6 @@ There is also a program that helps you translate automatically - all you have to - How to use basic [git](https://git-scm.com/) (cloning, pulling, committing, pushing) - How to run a [Python](https://www.python.org/) script +The script also shows you the ID of each bit of text you are translating, so that you can know where it is. `A.B` means string `B` in section `A`, `A.B.C` means string `C` in subsection `B` in section `A`, etc. + Clone the repository, then use the guided translation script (at `src/locales/guided_translation.py`) to update the translation files. You will need to pull before running, and commit/push your changes in order for them to be applied to CoinOS. -- cgit v1.2.3 From e54f0cf98d65e71153c4613a1e9a9b845b9f8f87 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Wed, 24 Aug 2022 16:04:40 -0500 Subject: reword language of new documentation --- doc/i18n.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/i18n.md b/doc/i18n.md index 7c180dcb..f33ab2de 100644 --- a/doc/i18n.md +++ b/doc/i18n.md @@ -60,9 +60,9 @@ You might notice that some of the left-text in the language files don't have a s }, ``` -These denote sections of the JSON file, which helps keep it organized. If you're translating a string that is in a section, make sure the translated string is in the same section of the new file. If that section doesn't exist, just create it. +These denote sections of the JSON file, which helps keep it organized. If you're translating some text that is in a section, make sure the translated text is in the same section of the new file. If that section doesn't exist, just create it. -In the translation files, sections roughly correspond to where the the strings are on CoinOS. This can be useful if you need context for a string. Here are some of these associations (`A.B` means section `B` is located inside `A`): +In the translation files, sections roughly correspond to where the the text is in CoinOS. This can be useful if you need context for some text. Here are some of these associations (`A.B` means section `B` is located inside `A`): | Section | Location | |-------------------|---------------------------------------------------| -- cgit v1.2.3