Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): add translation status #1689

Merged
merged 35 commits into from
Feb 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
cb2564f
feat(docs): add translation status table
edimitchel Feb 8, 2023
6defb07
Merge branch 'main' into feat/docs-translation-status
userquin Feb 8, 2023
e917b27
chore: include locales dts
userquin Feb 8, 2023
cf0af5a
chore: include initial compare version
userquin Feb 8, 2023
6d8171d
chore: update load files + logic
userquin Feb 8, 2023
fdda490
feat: flatten keys + update component
edimitchel Feb 9, 2023
6ff82d2
chore: remove unused deps
userquin Feb 9, 2023
c4a051b
chore: move translation status generation to script
userquin Feb 9, 2023
491b141
fix: add missing title on column
edimitchel Feb 9, 2023
7f657c5
chore: add codeflow link and file to json file
userquin Feb 9, 2023
a3398bd
Merge remote-tracking branch 'origin/feat/docs-translation-status' in…
userquin Feb 9, 2023
462e30e
chore: add some styles and add codeflow link
userquin Feb 9, 2023
f9c80b3
chore: add copy to clipboard logic
userquin Feb 9, 2023
4d141c1
chore: sort asc by translation completion
userquin Feb 9, 2023
3b95776
chore: add link to codelflow and fix dark caption
userquin Feb 9, 2023
aeba782
chore: add some ui stuff
userquin Feb 9, 2023
8dcc5f4
chore: update some ui stuff
userquin Feb 9, 2023
7490c0a
chore: cleanup styles
userquin Feb 9, 2023
a635902
chore: reduce pre size
userquin Feb 9, 2023
d9993ac
Merge branch 'main' into feat/docs-translation-status
userquin Feb 9, 2023
2c981a1
chore: update lock file
userquin Feb 9, 2023
c858991
fix: typecheck
userquin Feb 9, 2023
9f215b4
fix: typecheck .
userquin Feb 9, 2023
a5bb0ce
fix: typecheck, change scripts order
userquin Feb 9, 2023
4ed8266
chore: cleanup
userquin Feb 9, 2023
d19b39d
chore: add nuxi prepare on docs
userquin Feb 9, 2023
d7d71e6
fix: exclude translation state json file from linting
userquin Feb 9, 2023
d0b94df
fix: wring translation status file name
userquin Feb 9, 2023
824f982
chore: update nuxt and docs deps
userquin Feb 9, 2023
e002c9d
Merge branch 'main' into feat/docs-translation-status
userquin Feb 9, 2023
01c43e2
chore: resolve comments
userquin Feb 9, 2023
962fbe8
chore: downgrade nuxt and docs theme versions
userquin Feb 9, 2023
00e252d
fix: remove unused dep
edimitchel Feb 10, 2023
54c8aec
fix: only show open in codeflow if missing/oudated keys
edimitchel Feb 10, 2023
3c554b1
chore: remove codeflow svg from table actions
userquin Feb 11, 2023
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
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ public/
https-dev-config/localhost.crt
https-dev-config/localhost.key
Dockerfile
docs/translation-status.json
2 changes: 1 addition & 1 deletion config/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ const buildLocales = () => {
return useLocales.sort((a, b) => a.code.localeCompare(b.code))
}

const currentLocales = buildLocales()
export const currentLocales = buildLocales()

const datetimeFormats = Object.values(currentLocales).reduce((acc, data) => {
const dateTimeFormats = data.dateTimeFormats
Expand Down
1 change: 1 addition & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ dist
sw.*
.env
.output
translation-status.json
15 changes: 15 additions & 0 deletions docs/components/global/ClipboardIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script>
export default {
name: 'ClipboardIcon',
props: { copy: Boolean },
}
</script>

<template>
<svg v-if="copy" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2m-7 0a1 1 0 0 1 1 1a1 1 0 0 1-1 1a1 1 0 0 1-1-1a1 1 0 0 1 1-1M7 7h10V5h2v14H5V5h2v2Z" />
</svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2m-7 0a1 1 0 0 1 1 1a1 1 0 0 1-1 1a1 1 0 0 1-1-1a1 1 0 0 1 1-1M7 7h10V5h2v14H5V5h2v2m.5 6.5L9 12l2 2l4.5-4.5L17 11l-6 6l-3.5-3.5Z" />
</svg>
</template>
15 changes: 15 additions & 0 deletions docs/components/global/ToogleIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script>
export default {
name: 'ToogleIcon',
props: { up: Boolean },
}
</script>

<template>
<svg v-if="up" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
<path fill="currentColor" d="m12 10.828l-4.95 4.95l-1.414-1.414L12 8l6.364 6.364l-1.414 1.414z" />
</svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
<path fill="currentColor" d="m12 13.172l4.95-4.95l1.414 1.414L12 16L5.636 9.636L7.05 8.222z" />
</svg>
</template>
338 changes: 338 additions & 0 deletions docs/components/global/TranslationState.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,338 @@
<script setup lang="ts">
import type { TranslationStatus } from '../../types'

const localesStatuses: TranslationStatus = await import('../../translation-status.json').then(m => m.default)

const totalReference = localesStatuses.en.total

type Tab = 'missing' | 'outdated'

const hidden = ref(true)
const locale = ref()
const localeTab = ref<Tab>('missing')
const copied = ref(false)

const currentLocale = computed(() => {
if (hidden.value || !locale.value)
return undefined

return localesStatuses as Record<string, any>
})

const localeTitle = computed(() => {
if (hidden.value || !locale.value)
return undefined

return localeTab.value === 'missing'
? `Missing keys in ${locale.value.file}`
: `Outdated keys in ${locale.value.file}`
})

const missingEntries = computed<string[]>(() => {
if (hidden.value || !currentLocale.value || localeTab.value !== 'missing')
return []

return localesStatuses[locale.value].missing
})

const outdatedEntries = computed<string[]>(() => {
if (hidden.value || !currentLocale.value || localeTab.value !== 'outdated')
return []

return localesStatuses[locale.value]!.outdated
})

const showDetail = (key: string, tab: Tab = 'missing', fromTab = false) => {
if (key === locale.value && tab === localeTab.value) {
if (fromTab)
return

nextTick().then(() => hidden.value = !hidden.value)

return
}

locale.value = key
userquin marked this conversation as resolved.
Show resolved Hide resolved
localeTab.value = tab
nextTick().then(() => hidden.value = false)
}

const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText([
`# ${localeTitle.value}`,
(localeTab.value === 'missing' ? missingEntries.value : outdatedEntries.value).join('\n')].join('\n'),
)
copied.value = true
setTimeout(() => copied.value = false, 750)
}
catch {}
}
</script>

<template>
<div>
<table class="w-full">
<caption>
<div>You can see the detail (missing and outdated keys) by clicking on the corresponding row.</div>
<div>
If you want to send a PR, click on <strong>Edit</strong> link on the corresponding translation file, it will open <strong>Codeflow</strong>:
<NuxtLink
target="_blank"
href="https://developer.stackblitz.com/codeflow/working-in-codeflow-ide#making-a-pr-with-codeflow-ide"
title="How to make a PR with Codeflow IDE (opens in new window)"
>
read the following guide
</NuxtLink>
</div>
</caption>
<thead>
<tr>
<th>Language</th>
<th title="Keys correctly translated">
Translated
</th>
<th title="Keys missing from source which need translation for the language">
Missing
</th>
<th title="Keys which could be safely removed">
Outdated
</th>
<th>Total</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<template v-for="({ title, file, translated, missing, outdated, total, isSource }, key) in localesStatuses" :key="key">
<tr
v-if="totalReference > 0"
:class="[{ expandable: !isSource }]"
:title="!isSource ? 'Click to show detail' : undefined"
@click="!isSource && showDetail(key, 'missing')"
>
<td :class="[{ expandable: !isSource }]">
<div>
<ToogleIcon v-if="!isSource" :up="hidden || key !== locale" />
{{ title }}
</div>
</td>
<template v-if="isSource">
<td colspan="5" class="source-text">
<div>
{{ total }} keys as source
</div>
</td>
</template>
<template v-else>
<td>
<strong>{{ `${translated?.length ?? 0}` }}</strong> {{ `(${(100 * (translated?.length ?? 0) / totalReference).toFixed(1)}%)` }}
</td>
<td>
<strong>{{ `${missing?.length ?? 0}` }}</strong> {{ `(${(100 * (missing?.length ?? 0) / totalReference).toFixed(1)}%)` }}
</td>
<td>
<strong>{{ `${outdated?.length ?? 0}` }}</strong> {{ `(${(100 * (outdated?.length ?? 0) / totalReference).toFixed(1)}%)` }}
</td>
<td><strong>{{ `${total}` }}</strong></td>
<td>
<NuxtLink
v-if="outdated.length > 0 || missing.length > 0"
:href="`https://pr.new/github.com/elk-zone/elk/tree/main/locales/${file}`"
target="_blank"
class="codeflow"
title="Raise a PR with Codeflow (opens in new window)"
@click.stop
>
Edit
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
<path fill="currentColor" d="M5 21q-.825 0-1.413-.587Q3 19.825 3 19V5q0-.825.587-1.413Q4.175 3 5 3h7v2H5v14h14v-7h2v7q0 .825-.587 1.413Q19.825 21 19 21Zm4.7-5.3l-1.4-1.4L17.6 5H14V3h7v7h-2V6.4Z" />
</svg>
</NuxtLink>
</td>
</template>
</tr>
<template v-if="key === locale && !hidden">
<tr>
<td colspan="6">
<div class="detail">
<header>
<h2 class="tabs">
<button
:class="localeTab === 'missing' ? 'current' : null"
@click="showDetail(key, 'missing', true)"
>
Missing keys
</button>
<button
:class="localeTab === 'outdated' ? 'current' : null"
@click="showDetail(key, 'outdated', true)"
>
Outdated keys
</button>
</h2>
</header>
<ul v-if="localeTab === 'missing'">
<li v-for="entry in missingEntries" :key="entry">
<pre>{{ entry }}</pre>
</li>
</ul>
<ul v-else>
<li v-for="entry in outdatedEntries" :key="entry">
<pre>{{ entry }}</pre>
</li>
</ul>
<button @click="copyToClipboard()">
<ClipboardIcon :copy="!copied" />
Copy to clipboard
</button>
</div>
</td>
</tr>
</template>
</template>
</tbody>
</table>
</div>
</template>

<style scoped>
table {
font-size: 0.9rem;
width: 100%;
border-collapse: collapse;
border: 1px solid #ccc;
}

pre {
font-size: 0.75rem;
}

caption {
padding: 0.3rem;
background: #eee;
border: 1px solid #ccc;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border-bottom: none;
}
caption a {
text-decoration: underline;
}

th {
text-align: left;
border-bottom: 1px solid #ccc;
padding: 0.5rem;
}
th:not(:first-of-type),
td:not(:first-of-type) {
border-left: 1px solid #eee;
}
td {
padding: 0.5rem;
}
tr.expandable td:first-of-type {
padding-left: 4px;
}
tr.expandable, tr.expandable td {
cursor: pointer;
}

a.codeflow,
td.expandable div {
display: flex;
align-items: center;
flex-direction: row;
column-gap: 4px;
}
td.expandable > svg {
color: currentColor;
}

tbody tr td {
border-bottom: 1px solid #eee;
}

th[title] {
text-decoration: underline dotted white;
}

.source-text {
text-align: center;
font-weight: bold;
padding: 10px 0;
text-transform: uppercase;
}

.detail {
border: 1px solid #ccc;
border-radius: 3px;
}
.detail header {
padding: 0 0.3rem;
display: flex;
background: #eee;
justify-content: space-between;
align-items: center;
}

.detail header h2 button {
font-weight: bold;
padding: 0.5rem;
background-color: #eee;
}

.detail header .tabs button.current {
background-color: white;
}

.detail header .tabs + .heading-buttons {
display: flex;
flex-direction: row;
column-gap: 0.4rem;
align-items: center;
}

.detail ul {
padding: 0.3rem 0.5rem;
max-height: 250px;
min-height: 250px;
overflow-y: auto;
border-bottom: 1px solid #eee;
}

.detail > button {
display: flex;
/*justify-content: space-between;*/
align-items: center;
column-gap: 0.3rem;
padding: 0.3rem 0.5rem;
background: transparent;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 3px;
margin: 0.5rem;
}

@media (prefers-color-scheme: dark) {
.detail header {
background: #333;
color: #fff;
}

.detail header h2 button {
background-color: #333;
color: #fff;
}

.detail header .tabs button.current {
background-color: white;
color: #333;
}

table caption {
background: #333;
color: #fff;
}
}
</style>
Loading