forked from Mirrors/elk
feat: add translation status to language settings (#1717)
This commit is contained in:
parent
3e648f6fbc
commit
c5fe184281
10 changed files with 85 additions and 28 deletions
|
@ -9,4 +9,5 @@ public/
|
||||||
https-dev-config/localhost.crt
|
https-dev-config/localhost.crt
|
||||||
https-dev-config/localhost.key
|
https-dev-config/localhost.key
|
||||||
Dockerfile
|
Dockerfile
|
||||||
|
elk-translation-status.json
|
||||||
docs/translation-status.json
|
docs/translation-status.json
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,6 +9,7 @@ dist
|
||||||
.vite-inspect
|
.vite-inspect
|
||||||
.netlify/
|
.netlify/
|
||||||
.eslintcache
|
.eslintcache
|
||||||
|
elk-translation-status.json
|
||||||
|
|
||||||
public/shiki
|
public/shiki
|
||||||
public/emojis
|
public/emojis
|
||||||
|
|
|
@ -6,13 +6,10 @@
|
||||||
"dev": "nuxi dev",
|
"dev": "nuxi dev",
|
||||||
"build": "nuxi build",
|
"build": "nuxi build",
|
||||||
"generate": "nuxi generate",
|
"generate": "nuxi generate",
|
||||||
"preview": "nuxi preview",
|
"preview": "nuxi preview"
|
||||||
"prepare-translation-status": "nuxi prepare && esno scripts/prepare-translation-status.ts"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt-themes/docus": "^1.6.1",
|
"@nuxt-themes/docus": "^1.6.1",
|
||||||
"@types/flat": "^5.0.2",
|
|
||||||
"flat": "^5.0.2",
|
|
||||||
"nuxt": "^3.1.1"
|
"nuxt": "^3.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,6 +337,7 @@
|
||||||
"language": {
|
"language": {
|
||||||
"display_language": "Display Language",
|
"display_language": "Display Language",
|
||||||
"label": "Language",
|
"label": "Language",
|
||||||
|
"status": "Translation status: {0}/{1} ({2}%)",
|
||||||
"translations": {
|
"translations": {
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
"choose_language": "Choose language",
|
"choose_language": "Choose language",
|
||||||
|
|
|
@ -337,6 +337,7 @@
|
||||||
"language": {
|
"language": {
|
||||||
"display_language": "Idioma de pantalla",
|
"display_language": "Idioma de pantalla",
|
||||||
"label": "Idioma",
|
"label": "Idioma",
|
||||||
|
"status": "Estado traducción: {0}/{1} ({2}%)",
|
||||||
"translations": {
|
"translations": {
|
||||||
"add": "Agregar",
|
"add": "Agregar",
|
||||||
"choose_language": "Seleccionar idioma",
|
"choose_language": "Seleccionar idioma",
|
||||||
|
@ -405,16 +406,19 @@
|
||||||
"github_cards": "Tarjetas GitHub",
|
"github_cards": "Tarjetas GitHub",
|
||||||
"grayscale_mode": "Modo escala de grises",
|
"grayscale_mode": "Modo escala de grises",
|
||||||
"hide_account_hover_card": "Ocultar tarjeta flotante de cuenta",
|
"hide_account_hover_card": "Ocultar tarjeta flotante de cuenta",
|
||||||
|
"hide_alt_indi_on_posts": "Ocultar indicador ALT en publicaciones",
|
||||||
"hide_boost_count": "Ocultar contador de retoots",
|
"hide_boost_count": "Ocultar contador de retoots",
|
||||||
"hide_favorite_count": "Ocultar número de publicaciones favoritas",
|
"hide_favorite_count": "Ocultar número de publicaciones favoritas",
|
||||||
"hide_follower_count": "Ocultar número de seguidores",
|
"hide_follower_count": "Ocultar número de seguidores",
|
||||||
"hide_reply_count": "Ocultar número de respuestas",
|
"hide_reply_count": "Ocultar número de respuestas",
|
||||||
"hide_translation": "Ocultar traducción",
|
"hide_translation": "Ocultar traducción",
|
||||||
"hide_username_emojis": "Ocultar emojis en el nombre de usuario",
|
"hide_username_emojis": "Ocultar emojis en el nombre de usuario",
|
||||||
|
"hide_username_emojis_description": "Se ocultan los emojis en el nombre de usuario en las líneas de tiempo. Los emojis seguirán siendo visibles en sus perfiles.",
|
||||||
"label": "Preferencias",
|
"label": "Preferencias",
|
||||||
"title": "Funcionalidades experimentales",
|
"title": "Funcionalidades experimentales",
|
||||||
"user_picker": "Selector de usuarios",
|
"user_picker": "Selector de usuarios",
|
||||||
"virtual_scroll": "Desplazamiento virtual"
|
"virtual_scroll": "Desplazamiento virtual",
|
||||||
|
"wellbeing": "Bienestar"
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"appearance": {
|
"appearance": {
|
||||||
|
@ -463,8 +467,10 @@
|
||||||
"filter_removed_phrase": "Eliminado por filtrado",
|
"filter_removed_phrase": "Eliminado por filtrado",
|
||||||
"filter_show_anyway": "Mostrar de todas formas",
|
"filter_show_anyway": "Mostrar de todas formas",
|
||||||
"img_alt": {
|
"img_alt": {
|
||||||
|
"ALT": "ALT",
|
||||||
"desc": "Descripción",
|
"desc": "Descripción",
|
||||||
"dismiss": "Descartar"
|
"dismiss": "Descartar",
|
||||||
|
"read": "Leer la descripción de la imagen {0}"
|
||||||
},
|
},
|
||||||
"poll": {
|
"poll": {
|
||||||
"count": "{0} votos|{0} voto|{0} votos",
|
"count": "{0} votos|{0} voto|{0} votos",
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
"test:typecheck": "stale-dep && vue-tsc --noEmit && vue-tsc --noEmit --project service-worker/tsconfig.json",
|
"test:typecheck": "stale-dep && vue-tsc --noEmit && vue-tsc --noEmit --project service-worker/tsconfig.json",
|
||||||
"test": "nr test:unit",
|
"test": "nr test:unit",
|
||||||
"update:team:avatars": "esno scripts/avatars.ts",
|
"update:team:avatars": "esno scripts/avatars.ts",
|
||||||
"prepare-translation-status": "pnpm -C docs run prepare-translation-status",
|
"prepare-translation-status": "esno scripts/prepare-translation-status.ts",
|
||||||
"postinstall": "ignore-dependency-scripts \"stale-dep -u && simple-git-hooks && nuxi prepare && nr prepare-translation-status\"",
|
"postinstall": "ignore-dependency-scripts \"stale-dep -u && simple-git-hooks && nuxi prepare && nr prepare-translation-status\"",
|
||||||
"release": "stale-dep && bumpp && esno scripts/release.ts"
|
"release": "stale-dep && bumpp && esno scripts/release.ts"
|
||||||
},
|
},
|
||||||
|
@ -110,6 +110,7 @@
|
||||||
"@nuxt/devtools": "^0.1.0",
|
"@nuxt/devtools": "^0.1.0",
|
||||||
"@types/chroma-js": "^2.1.4",
|
"@types/chroma-js": "^2.1.4",
|
||||||
"@types/file-saver": "^2.0.5",
|
"@types/file-saver": "^2.0.5",
|
||||||
|
"@types/flat": "^5.0.2",
|
||||||
"@types/fnando__sparkline": "^0.3.4",
|
"@types/fnando__sparkline": "^0.3.4",
|
||||||
"@types/fs-extra": "^11.0.1",
|
"@types/fs-extra": "^11.0.1",
|
||||||
"@types/js-yaml": "^4.0.5",
|
"@types/js-yaml": "^4.0.5",
|
||||||
|
@ -118,6 +119,7 @@
|
||||||
"bumpp": "^8.2.1",
|
"bumpp": "^8.2.1",
|
||||||
"eslint": "^8.32.0",
|
"eslint": "^8.32.0",
|
||||||
"esno": "^0.16.3",
|
"esno": "^0.16.3",
|
||||||
|
"flat": "^5.0.2",
|
||||||
"fs-extra": "^11.1.0",
|
"fs-extra": "^11.1.0",
|
||||||
"lint-staged": "^13.1.0",
|
"lint-staged": "^13.1.0",
|
||||||
"nuxt": "3.1.1",
|
"nuxt": "3.1.1",
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { t } = useI18n()
|
import type { ElkTranslationStatus } from '~/types/translation-status'
|
||||||
|
|
||||||
|
const { t, locale } = useI18n()
|
||||||
|
|
||||||
|
const translationStatus: ElkTranslationStatus = await import('~/elk-translation-status.json').then(m => m.default)
|
||||||
|
|
||||||
useHeadFixed({
|
useHeadFixed({
|
||||||
title: () => `${t('settings.language.label')} | ${t('nav.settings')}`,
|
title: () => `${t('settings.language.label')} | ${t('nav.settings')}`,
|
||||||
})
|
})
|
||||||
|
const status = computed(() => {
|
||||||
|
const entry = translationStatus.locales[locale.value]
|
||||||
|
return t('settings.language.status', [entry.total, translationStatus.total, entry.percentage])
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -15,7 +23,10 @@ useHeadFixed({
|
||||||
</template>
|
</template>
|
||||||
<div p6>
|
<div p6>
|
||||||
<label space-y-2>
|
<label space-y-2>
|
||||||
<p font-medium>{{ $t('settings.language.display_language') }}</p>
|
<span block font-medium>{{ $t('settings.language.display_language') }}</span>
|
||||||
|
<span block>
|
||||||
|
{{ status }}
|
||||||
|
</span>
|
||||||
<SettingsLanguage select-settings />
|
<SettingsLanguage select-settings />
|
||||||
</label>
|
</label>
|
||||||
<h2 py4 mt2 font-bold text-xl flex="~ gap-1" items-center>
|
<h2 py4 mt2 font-bold text-xl flex="~ gap-1" items-center>
|
||||||
|
|
|
@ -59,6 +59,7 @@ importers:
|
||||||
'@tiptap/vue-3': 2.0.0-beta.204
|
'@tiptap/vue-3': 2.0.0-beta.204
|
||||||
'@types/chroma-js': ^2.1.4
|
'@types/chroma-js': ^2.1.4
|
||||||
'@types/file-saver': ^2.0.5
|
'@types/file-saver': ^2.0.5
|
||||||
|
'@types/flat': ^5.0.2
|
||||||
'@types/fnando__sparkline': ^0.3.4
|
'@types/fnando__sparkline': ^0.3.4
|
||||||
'@types/fs-extra': ^11.0.1
|
'@types/fs-extra': ^11.0.1
|
||||||
'@types/js-yaml': ^4.0.5
|
'@types/js-yaml': ^4.0.5
|
||||||
|
@ -80,6 +81,7 @@ importers:
|
||||||
eslint: ^8.32.0
|
eslint: ^8.32.0
|
||||||
esno: ^0.16.3
|
esno: ^0.16.3
|
||||||
file-saver: ^2.0.5
|
file-saver: ^2.0.5
|
||||||
|
flat: ^5.0.2
|
||||||
floating-vue: 2.0.0-beta.20
|
floating-vue: 2.0.0-beta.20
|
||||||
focus-trap: ^7.2.0
|
focus-trap: ^7.2.0
|
||||||
form-data: ^4.0.0
|
form-data: ^4.0.0
|
||||||
|
@ -197,7 +199,7 @@ importers:
|
||||||
ultrahtml: 1.2.0
|
ultrahtml: 1.2.0
|
||||||
unimport: 2.1.0
|
unimport: 2.1.0
|
||||||
unplugin-auto-import: 0.13.0_@vueuse+core@9.11.1
|
unplugin-auto-import: 0.13.0_@vueuse+core@9.11.1
|
||||||
vite-plugin-pwa: 0.14.1_tz3vz2xt4jvid2diblkpydcyn4
|
vite-plugin-pwa: 0.14.1
|
||||||
vue-advanced-cropper: 2.8.8
|
vue-advanced-cropper: 2.8.8
|
||||||
vue-virtual-scroller: 2.0.0-beta.7
|
vue-virtual-scroller: 2.0.0-beta.7
|
||||||
workbox-build: 6.5.4
|
workbox-build: 6.5.4
|
||||||
|
@ -208,6 +210,7 @@ importers:
|
||||||
'@nuxt/devtools': 0.1.0_nuxt@3.1.1
|
'@nuxt/devtools': 0.1.0_nuxt@3.1.1
|
||||||
'@types/chroma-js': 2.1.4
|
'@types/chroma-js': 2.1.4
|
||||||
'@types/file-saver': 2.0.5
|
'@types/file-saver': 2.0.5
|
||||||
|
'@types/flat': 5.0.2
|
||||||
'@types/fnando__sparkline': 0.3.4
|
'@types/fnando__sparkline': 0.3.4
|
||||||
'@types/fs-extra': 11.0.1
|
'@types/fs-extra': 11.0.1
|
||||||
'@types/js-yaml': 4.0.5
|
'@types/js-yaml': 4.0.5
|
||||||
|
@ -216,6 +219,7 @@ importers:
|
||||||
bumpp: 8.2.1
|
bumpp: 8.2.1
|
||||||
eslint: 8.32.0
|
eslint: 8.32.0
|
||||||
esno: 0.16.3
|
esno: 0.16.3
|
||||||
|
flat: 5.0.2
|
||||||
fs-extra: 11.1.0
|
fs-extra: 11.1.0
|
||||||
lint-staged: 13.1.0
|
lint-staged: 13.1.0
|
||||||
nuxt: 3.1.1_7rz7g5sqfnn6wuv5lem37retty
|
nuxt: 3.1.1_7rz7g5sqfnn6wuv5lem37retty
|
||||||
|
@ -228,13 +232,9 @@ importers:
|
||||||
docs:
|
docs:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@nuxt-themes/docus': ^1.6.1
|
'@nuxt-themes/docus': ^1.6.1
|
||||||
'@types/flat': ^5.0.2
|
|
||||||
flat: ^5.0.2
|
|
||||||
nuxt: ^3.1.1
|
nuxt: ^3.1.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nuxt-themes/docus': 1.6.3_nuxt@3.1.1
|
'@nuxt-themes/docus': 1.6.3_nuxt@3.1.1
|
||||||
'@types/flat': 5.0.2
|
|
||||||
flat: 5.0.2
|
|
||||||
nuxt: 3.1.1
|
nuxt: 3.1.1
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
@ -11797,12 +11797,10 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite-plugin-pwa/0.14.1_tz3vz2xt4jvid2diblkpydcyn4:
|
/vite-plugin-pwa/0.14.1:
|
||||||
resolution: {integrity: sha512-5zx7yhQ8RTLwV71+GA9YsQQ63ALKG8XXIMqRJDdZkR8ZYftFcRgnzM7wOWmQZ/DATspyhPih5wCdcZnAIsM+mA==}
|
resolution: {integrity: sha512-5zx7yhQ8RTLwV71+GA9YsQQ63ALKG8XXIMqRJDdZkR8ZYftFcRgnzM7wOWmQZ/DATspyhPih5wCdcZnAIsM+mA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^3.1.0 || ^4.0.0
|
vite: ^3.1.0 || ^4.0.0
|
||||||
workbox-build: ^6.5.4
|
|
||||||
workbox-window: ^6.5.4
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rollup/plugin-replace': 5.0.2_rollup@3.10.1
|
'@rollup/plugin-replace': 5.0.2_rollup@3.10.1
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
|
@ -11812,6 +11810,7 @@ packages:
|
||||||
workbox-build: 6.5.4
|
workbox-build: 6.5.4
|
||||||
workbox-window: 6.5.4
|
workbox-window: 6.5.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
- '@types/babel__core'
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { flatten } from 'flat'
|
import flatten from 'flat'
|
||||||
import { createResolver } from '@nuxt/kit'
|
import { createResolver } from '@nuxt/kit'
|
||||||
import { readFile, writeFile } from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import { currentLocales } from '../../config/i18n'
|
import { currentLocales } from '../config/i18n'
|
||||||
import vsCodeConfig from '../../.vscode/settings.json'
|
import vsCodeConfig from '../.vscode/settings.json'
|
||||||
import type { LocaleEntry } from '../types'
|
import type { LocaleEntry } from '../docs/types'
|
||||||
|
import type { ElkTranslationStatus } from '~/types/translation-status'
|
||||||
|
|
||||||
export const localeData: [code: string, file: string[], title: string][]
|
export const localeData: [code: string, file: string[], title: string][]
|
||||||
= currentLocales.map((l: any) => [l.code, l.files ? l.files : [l.file!], l.name ?? l.code])
|
= currentLocales.map((l: any) => [l.code, l.files ? l.files : [l.file!], l.name ?? l.code])
|
||||||
|
@ -27,7 +28,7 @@ async function readI18nFile(file: string | string[]) {
|
||||||
if (Array.isArray(file)) {
|
if (Array.isArray(file)) {
|
||||||
const files = await Promise.all(file.map(f => async () => {
|
const files = await Promise.all(file.map(f => async () => {
|
||||||
return JSON.parse(Buffer.from(
|
return JSON.parse(Buffer.from(
|
||||||
await readFile(resolver.resolve(`../../locales/${f}`), 'utf-8'),
|
await fs.readFile(resolver.resolve(`../locales/${f}`), 'utf-8'),
|
||||||
).toString())
|
).toString())
|
||||||
})).then(f => f.map(f => f()))
|
})).then(f => f.map(f => f()))
|
||||||
const data: Record<string, any> = files[0]
|
const data: Record<string, any> = files[0]
|
||||||
|
@ -37,7 +38,7 @@ async function readI18nFile(file: string | string[]) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return JSON.parse(Buffer.from(
|
return JSON.parse(Buffer.from(
|
||||||
await readFile(resolver.resolve(`../../locales/${file}`), 'utf-8'),
|
await fs.readFile(resolver.resolve(`../locales/${file}`), 'utf-8'),
|
||||||
).toString())
|
).toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,6 +62,7 @@ async function prepareTranslationStatus() {
|
||||||
const sourceLanguageLocale = localeData.find(l => l[0] === vsCodeConfig['i18n-ally.sourceLanguage'])!
|
const sourceLanguageLocale = localeData.find(l => l[0] === vsCodeConfig['i18n-ally.sourceLanguage'])!
|
||||||
const entries: Record<string, any> = await readI18nFile(sourceLanguageLocale[1])
|
const entries: Record<string, any> = await readI18nFile(sourceLanguageLocale[1])
|
||||||
const flatEntries = flatten<typeof entries, Record<string, string>>(entries)
|
const flatEntries = flatten<typeof entries, Record<string, string>>(entries)
|
||||||
|
const total = Object.keys(flatEntries).length
|
||||||
const data: Record<string, LocaleEntry> = {
|
const data: Record<string, LocaleEntry> = {
|
||||||
en: {
|
en: {
|
||||||
translated: [],
|
translated: [],
|
||||||
|
@ -68,13 +70,12 @@ async function prepareTranslationStatus() {
|
||||||
missing: [],
|
missing: [],
|
||||||
outdated: [],
|
outdated: [],
|
||||||
title: 'English (source)',
|
title: 'English (source)',
|
||||||
total: Object.keys(flatEntries).length,
|
total,
|
||||||
isSource: true,
|
isSource: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(localeData.filter(l => l[0] !== 'en-US').map(async ([code, file, title]) => {
|
await Promise.all(localeData.filter(l => l[0] !== 'en-US').map(async ([code, file, title]) => {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.info(`Comparing ${code}...`, title)
|
console.info(`Comparing ${code}...`, title)
|
||||||
data[code] = {
|
data[code] = {
|
||||||
title,
|
title,
|
||||||
|
@ -95,11 +96,42 @@ async function prepareTranslationStatus() {
|
||||||
sorted[k] = { ...data[k] }
|
sorted[k] = { ...data[k] }
|
||||||
})
|
})
|
||||||
|
|
||||||
await writeFile(
|
const resolver = createResolver(import.meta.url)
|
||||||
createResolver(import.meta.url).resolve('../translation-status.json'),
|
|
||||||
|
await fs.writeFile(
|
||||||
|
resolver.resolve('../docs/translation-status.json'),
|
||||||
JSON.stringify(sorted, null, 2),
|
JSON.stringify(sorted, null, 2),
|
||||||
{ encoding: 'utf-8' },
|
{ encoding: 'utf-8' },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const translationStatus: ElkTranslationStatus = {
|
||||||
|
total,
|
||||||
|
locales: {
|
||||||
|
'en-US': {
|
||||||
|
total,
|
||||||
|
percentage: '100',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(data).filter(k => k !== 'en').forEach((e) => {
|
||||||
|
const percentage = total <= 0.0 || data[e].total === 0.0
|
||||||
|
? '0'
|
||||||
|
: data[e].total === total
|
||||||
|
? '100'
|
||||||
|
: ((data[e].translated.length / total) * 100).toFixed(1)
|
||||||
|
|
||||||
|
translationStatus.locales[e] = {
|
||||||
|
total: data[e].total,
|
||||||
|
percentage,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await fs.writeFile(
|
||||||
|
resolver.resolve('../elk-translation-status.json'),
|
||||||
|
JSON.stringify(translationStatus, null, 2),
|
||||||
|
{ encoding: 'utf-8' },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareTranslationStatus()
|
prepareTranslationStatus()
|
7
types/translation-status.ts
Normal file
7
types/translation-status.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export interface ElkTranslationStatus {
|
||||||
|
total: number
|
||||||
|
locales: Record<string, {
|
||||||
|
percentage: string
|
||||||
|
total: number
|
||||||
|
}>
|
||||||
|
}
|
Loading…
Reference in a new issue