feat(org): Added translation status page
This commit is contained in:
parent
7a4f47e50f
commit
a2b689e69a
8 changed files with 271 additions and 0 deletions
|
@ -319,6 +319,8 @@ org:
|
|||
'algoliasearch': *algoliasearch
|
||||
'react-copy-to-clipboard': 5.1.0
|
||||
'daisyui': *daisyui
|
||||
'echarts': 5.4.2
|
||||
'echarts-for-react': 3.0.2
|
||||
'jotai': &jotai '2.2.1'
|
||||
'jotai-location': &jotai-location '0.5.1'
|
||||
'lodash.get': *_get
|
||||
|
|
103
sites/org/components/crowdin/status.mjs
Normal file
103
sites/org/components/crowdin/status.mjs
Normal file
|
@ -0,0 +1,103 @@
|
|||
import { useState, useEffect } from 'react'
|
||||
import { siteConfig } from 'site/site.config.mjs'
|
||||
import { Spinner } from 'shared/components/spinner.mjs'
|
||||
import { ChartWrapper } from 'shared/components/wrappers/chart.mjs'
|
||||
import orderBy from 'lodash.orderby'
|
||||
|
||||
/*
|
||||
* This method load the translation status from the Crowdin API
|
||||
*/
|
||||
const loadTranslationStatus = async (setter) => {
|
||||
let response
|
||||
try {
|
||||
response = await fetch(
|
||||
`https://api.crowdin.com/api/v2/projects/${siteConfig.crowdin.projectId}/languages/progress`,
|
||||
{ headers: { Authorization: `Bearer ${siteConfig.crowdin.token}` } }
|
||||
)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
setter(err)
|
||||
}
|
||||
if (response) {
|
||||
const data = await response.json()
|
||||
setter(data)
|
||||
}
|
||||
}
|
||||
|
||||
const Status = ({ done, approved, language }) => {
|
||||
const option = {
|
||||
series: [
|
||||
{
|
||||
name: 'Translation Status',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
emphasis: {
|
||||
disabled: true,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: approved,
|
||||
name: 'Translated & Approved',
|
||||
itemStyle: {
|
||||
color: 'currentColor',
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
value: done,
|
||||
name: 'Translated & Approved',
|
||||
itemStyle: {
|
||||
color: 'currentColor',
|
||||
opacity: 0.7,
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 100 - (done + approved),
|
||||
name: 'Untranslated',
|
||||
itemStyle: {
|
||||
color: 'currentColor',
|
||||
opacity: 0.3,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return <ChartWrapper option={option} h={150} />
|
||||
}
|
||||
|
||||
export const TranslationStatus = () => {
|
||||
const [status, setStatus] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!status) loadTranslationStatus(setStatus)
|
||||
}, [status])
|
||||
|
||||
return status ? (
|
||||
<>
|
||||
<div className="text-primary flex flex-row flex-wrap items-center space-around w-full">
|
||||
{status.data &&
|
||||
orderBy(status.data, ['data.approvalProgress'], ['desc']).map((entry) => (
|
||||
<div className="text-center" key={entry.data.languageId} style={{ width: '150px' }}>
|
||||
<h5>
|
||||
{entry.data.languageId.indexOf('-') === -1
|
||||
? entry.data.languageId.toUpperCase()
|
||||
: entry.data.languageId.split('-')[0].toUpperCase()}
|
||||
: {entry.data.approvalProgress}%
|
||||
</h5>
|
||||
<Status
|
||||
done={entry.data.translationProgress - entry.data.approvalProgress}
|
||||
approved={entry.data.approvalProgress}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<Spinner className="w-24 h-24 m-auto text-primary animate-spin" />
|
||||
)
|
||||
}
|
|
@ -89,6 +89,11 @@ const sitePages = (t = false, control = 99) => {
|
|||
s: 'profile',
|
||||
h: 1,
|
||||
},
|
||||
translation: {
|
||||
t: t('translation'),
|
||||
s: 'translation',
|
||||
h: 1,
|
||||
},
|
||||
sitemap: {
|
||||
t: t('sitemap'),
|
||||
s: 'sitemap',
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
"algoliasearch": "4.18.0",
|
||||
"react-copy-to-clipboard": "5.1.0",
|
||||
"daisyui": "3.1.7",
|
||||
"echarts": "5.4.2",
|
||||
"echarts-for-react": "3.0.2",
|
||||
"jotai": "2.2.1",
|
||||
"jotai-location": "0.5.1",
|
||||
"lodash.get": "4.4.2",
|
||||
|
|
102
sites/org/pages/translation/index.mjs
Normal file
102
sites/org/pages/translation/index.mjs
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Dependencies
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
// Components
|
||||
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
|
||||
import { BareLayout as Layout } from 'site/components/layouts/bare.mjs'
|
||||
import { TranslationStatus } from 'site/components/crowdin/status.mjs'
|
||||
import { Popout } from 'shared/components/popout.mjs'
|
||||
import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs'
|
||||
import { WebLink } from 'shared/components/web-link.mjs'
|
||||
|
||||
// Translation namespaces used on this page
|
||||
const namespaces = [...new Set(pageNs)]
|
||||
|
||||
// FIXME: This page (ironically) lacks translation
|
||||
//
|
||||
const TranslationPage = ({ page }) => (
|
||||
<PageWrapper {...page} layout={Layout}>
|
||||
<div className="max-w-6xl mx-auto p-4 mt-4">
|
||||
<Breadcrumbs crumbs={[{ s: 'translation', t: 'Translation' }]} title="Translation" />
|
||||
<h1>Translation</h1>
|
||||
<p>
|
||||
Thanks to the translation volunteers in our community FreeSewing is proudly multilingual.
|
||||
</p>
|
||||
|
||||
<h2>Get involved</h2>
|
||||
<p>
|
||||
Translation is a team effort, and getting involved is not hard at all. Refer to{' '}
|
||||
<WebLink href="https://freesewing.dev/guides/translation" txt="the translation guide" /> for
|
||||
all details.
|
||||
</p>
|
||||
|
||||
<h2>Translation Status</h2>
|
||||
<TranslationStatus />
|
||||
<b className="ml-10">Legend</b>
|
||||
<ul className="list list-inside ml-4">
|
||||
<li className="flex flex-row items-center gap-2">
|
||||
<span className="inline-block w-4 h-4 rounded-full bg-primary"></span>
|
||||
<span>Translated & Approved</span>
|
||||
</li>
|
||||
<li className="flex flex-row items-center gap-2">
|
||||
<span className="inline-block w-4 h-4 rounded-full bg-primary bg-opacity-70"></span>
|
||||
<span>Translated but not (yet) approved</span>
|
||||
</li>
|
||||
<li className="flex flex-row items-center gap-2">
|
||||
<span className="inline-block w-4 h-4 rounded-full bg-primary bg-opacity-30"></span>
|
||||
<span>Not translated (yet)</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Supported Languages</h2>
|
||||
<p>We currently support the following five languages:</p>
|
||||
<ul className="list list-inside list-disc ml-4">
|
||||
<li>
|
||||
<b>English</b>{' '}
|
||||
<small>
|
||||
(This is our source language and the working language of the FreeSewing project)
|
||||
</small>
|
||||
</li>
|
||||
<li>
|
||||
<b>Dutch</b>
|
||||
</li>
|
||||
<li>
|
||||
<b>German</b>
|
||||
</li>
|
||||
<li>
|
||||
<b>French</b>
|
||||
</li>
|
||||
<li>
|
||||
<b>Spanish</b>
|
||||
</li>
|
||||
</ul>
|
||||
<p>In addition, comminity members have started initiatives to add the following langauges:</p>
|
||||
<ul className="list list-inside list-disc ml-4">
|
||||
<li>
|
||||
<b>Ukranian</b>
|
||||
</li>
|
||||
</ul>
|
||||
<Popout tip>
|
||||
<h5>Looking to add a language?</h5>
|
||||
<p>
|
||||
We would love to make FreeSewing available in more langauges.
|
||||
<br />
|
||||
If you are interested in starting a new translation effort, please reach out.
|
||||
</p>
|
||||
</Popout>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
)
|
||||
|
||||
export default TranslationPage
|
||||
|
||||
export async function getStaticProps({ locale }) {
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale, namespaces)),
|
||||
page: {
|
||||
locale,
|
||||
path: ['translation'],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
|
@ -7,11 +7,16 @@ export const siteConfig = {
|
|||
bugsnag: {
|
||||
key: '1b3a900d6ebbfd071975e39b534e1ff5',
|
||||
},
|
||||
crowdin: {
|
||||
projectId: 356411,
|
||||
token: '77cf8abfabef66e1275cd4ddfe0c857d45db5e51e8349877dc50a7a740d28fb573e8a4543eca616b', // Translation status (Read-only)
|
||||
},
|
||||
sanity: {
|
||||
project: process.env.SANITY_PROJECT || 'hl5bw8cj',
|
||||
dataset: 'site-content',
|
||||
apiVersion: '2023-06-17',
|
||||
},
|
||||
languages: ['en', 'es', 'de', 'fr', 'nl'],
|
||||
languagesWip: ['uk'],
|
||||
site: 'FreeSewing.org',
|
||||
}
|
||||
|
|
19
sites/shared/components/wrappers/chart.mjs
Normal file
19
sites/shared/components/wrappers/chart.mjs
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { useState } from 'react'
|
||||
import * as echarts from 'echarts'
|
||||
import ReactECharts from 'echarts-for-react'
|
||||
import { Popout } from 'shared/components/popout.mjs'
|
||||
|
||||
echarts.registerTheme('light', {
|
||||
backgroundColor: 'transparent',
|
||||
})
|
||||
echarts.registerTheme('dark', {
|
||||
backgroundColor: 'transparent',
|
||||
})
|
||||
|
||||
export const ChartWrapper = ({ option = false, theme = 'light', h = 400 }) => {
|
||||
return option ? (
|
||||
<ReactECharts option={option} className="class_2" theme={theme} style={{ height: h }} />
|
||||
) : (
|
||||
<Popout loading>Loading chart...</Popout>
|
||||
)
|
||||
}
|
33
yarn.lock
33
yarn.lock
|
@ -7894,6 +7894,22 @@ ecdsa-sig-formatter@1.0.11:
|
|||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
echarts-for-react@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/echarts-for-react/-/echarts-for-react-3.0.2.tgz#ac5859157048a1066d4553e34b328abb24f2b7c1"
|
||||
integrity sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.3"
|
||||
size-sensor "^1.0.1"
|
||||
|
||||
echarts@^5.4.2:
|
||||
version "5.4.2"
|
||||
resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.4.2.tgz#9f38781c9c6ae323e896956178f6956952c77a48"
|
||||
integrity sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==
|
||||
dependencies:
|
||||
tslib "2.3.0"
|
||||
zrender "5.4.3"
|
||||
|
||||
editorconfig@^0.15.3:
|
||||
version "0.15.3"
|
||||
resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5"
|
||||
|
@ -18126,6 +18142,11 @@ sisteransi@^1.0.5:
|
|||
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
|
||||
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
|
||||
|
||||
size-sensor@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/size-sensor/-/size-sensor-1.0.1.tgz#f84e46206d3e259faff1d548e4b3beca93219dbb"
|
||||
integrity sha512-QTy7MnuugCFXIedXRpUSk9gUnyNiaxIdxGfUjr8xxXOqIB3QvBUYP9+b51oCg2C4dnhaeNk/h57TxjbvoJrJUA==
|
||||
|
||||
slash@3.0.0, slash@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||
|
@ -19392,6 +19413,11 @@ tsconfig-paths@^4.1.2:
|
|||
minimist "^1.2.6"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tslib@2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
|
||||
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||
|
||||
tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
|
@ -20723,6 +20749,13 @@ zod@3.21.4:
|
|||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db"
|
||||
integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==
|
||||
|
||||
zrender@5.4.3:
|
||||
version "5.4.3"
|
||||
resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.4.3.tgz#41ffaf835f3a3210224abd9d6964b48ff01e79f5"
|
||||
integrity sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==
|
||||
dependencies:
|
||||
tslib "2.3.0"
|
||||
|
||||
zwitch@^1.0.0:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue