Internationalization upgrades (PR 13)

commit 56e4933c639ff32ea18470ae1534fa4d06b448e3
Author: root <root@git.maharshi.ninja>
Date:   Tue Jan 4 11:09:22 2022 +0530

    Also format dates

commit 01d379537b2e41819e2093b33dfd2a026bcb7281
Author: root <root@git.maharshi.ninja>
Date:   Sun Jan 2 13:48:36 2022 +0530

    Another Bengali translation update

commit 53063d4265f85db7be14135ffaa095647f233841
Author: root <root@git.maharshi.ninja>
Date:   Sat Jan 1 11:41:44 2022 +0530

    Standardize to BCP47 and adjust

commit 1b48f79cce411f8d18cf9e5059916b1c50719cd5
Author: root <root@git.maharshi.ninja>
Date:   Sat Jan 1 11:17:28 2022 +0530

    Localized number formatting + Bengali translations update

commit 6b3e30db37338334f03d98b92d124741446fb470
Author: root <root@git.maharshi.ninja>
Date:   Sat Jan 1 10:41:27 2022 +0530

    Fix fontloading

commit 5b08962971f8edb5030bc5ba79972bbb209b3d31
Author: root <root@git.maharshi.ninja>
Date:   Sat Jan 1 10:38:29 2022 +0530

    Even more standardization

commit bc6a4dfb335647472ea091b302b627f475bed879
Author: root <root@git.maharshi.ninja>
Date:   Sat Jan 1 10:25:29 2022 +0530

    Rename as per BCP-47 and standardize

commit 106f84fa0486d19504fd244aaab41f9cd4a8a513
Author: root <root@git.maharshi.ninja>
Date:   Sat Jan 1 10:13:32 2022 +0530

    i18n on steroids
This commit is contained in:
root
2022-01-07 11:05:37 +05:30
parent 2465dc50f0
commit ab35cdb92f
21 changed files with 114 additions and 112 deletions
+7 -7
View File
@@ -110,20 +110,20 @@ export default {
data: () => ({
languageOptions: [
{ value: 'zh_Hant', text: 'Chinese (Traditional)' },
{ value: 'en', text: 'English' },
{ value: 'fr', text: 'French' },
{ value: 'de', text: 'German' },
{ value: 'el', text: 'Greek' },
{ value: 'zh_Hans', text: 'Chinese (Simplified, only loads the font)' },
{ value: 'jp', text: 'Japanese (only loads fonts)' },
{ value: 'kr', text: 'Korean (only loads fonts)' },
{ value: 'cyrl', text: 'Cyrillic Languages (fonts)' },
{ value: 'zh-Hans', text: 'Chinese (Simplified, only loads the font)' },
{ value: 'zh-Hant', text: 'Chinese (Traditional)' },
{ value: 'ja', text: 'Japanese (only loads fonts)' },
{ value: 'ko', text: 'Korean (only loads fonts)' },
{ value: 'ru', text: 'Russian (only loads fonts)' },
{ value: 'lt', text: 'Lithuanian' },
{ value: 'ml', text: 'Malayalam' },
{ value: 'nb_NO', text: 'Norwegian Bokmål' },
{ value: 'nb-NO', text: 'Norwegian Bokmål' },
{ value: 'tr', text: 'Turkish' },
{ value: 'bn_beng', text: 'Bengali (বাংলা)' }
{ value: 'bn-Beng', text: 'Bengali (বাংলা)' }
// Incomplete, DO NOT USE
/* { value: 'bn_latn', text: 'Bengali (Latin)' }, */
].sort((a, b) => {
+2 -4
View File
@@ -10,18 +10,16 @@
</template>
<script>
import { LibPiped } from '@/tools/libpiped'
export default {
name: 'ExpandableDate',
props: ['date'],
computed: {
timeAgo () {
return LibPiped.timeAgo(this.date)
return this.$store.getters['i18n/fmtRelative'](this.date)
},
formattedDate () {
return LibPiped.formatFullDate(this.date)
return this.$store.getters['i18n/fmtDateTime'](this.date)
}
}
}
+1 -4
View File
@@ -17,7 +17,7 @@
<v-divider class="my-2" />
<v-icon>mdi-thumb-up</v-icon> {{ numberFormat(comment.likeCount) }}
<v-icon>mdi-thumb-up</v-icon> {{ this.$store.getters['i18n/fmtNumber'](comment.likeCount) }}
<v-icon v-if="comment.hearted" class="ml-4">mdi-heart</v-icon>
<br />
<v-btn class="mt-1" text :loading="requestInProgress" :disabled="requestInProgress" @click="loadReplies" v-if="!subComment && childComments.length === 0 && comment.repliesPage != null">Load Replies</v-btn>
@@ -45,9 +45,6 @@ export default {
childComments: []
}),
methods: {
numberFormat (...args) {
return LibPiped.numberFormat(...args)
},
async loadReplies () {
let nextpage = null
this.requestInProgress = true
+1 -6
View File
@@ -14,7 +14,7 @@
<h5 @click="navigate" @keypress.enter="navigate" role="link">{{ video.uploaderName || video.uploader }}</h5>
</router-link>
<slot />
{{ $tc('counts.views', video.views, { n: numberFormat(video.views) }) }}<br />
{{ $tc('counts.views', video.views, { n: this.$store.getters['i18n/fmtNumber'](video.views) }) }}<br />
{{ video.uploadedDate }} <br />
{{ timeFormat(video.duration) }}
</v-card-text>
@@ -74,11 +74,6 @@ export default {
}
}
},
numberFormat (...args) {
return LibPiped.numberFormat(...args)
},
timeFormat (...args) {
return LibPiped.timeFormat(...args)
}
+10 -8
View File
@@ -4,7 +4,7 @@ import App from './App.vue'
import '@mdi/font/css/materialdesignicons.min.css'
import '@/styles/main.scss'
import { i18n } from '@/plugins/i18n'
import { i18n, i18nInitialized } from '@/plugins/i18n'
import vuetify from '@/plugins/vuetify'
import store from '@/store'
import router from '@/router'
@@ -13,10 +13,12 @@ import './registerServiceWorker'
Vue.config.productionTip = false
new Vue({
vuetify,
i18n,
store,
router,
render: h => h(App)
}).$mount('#app')
i18nInitialized.then(() => {
new Vue({
vuetify,
i18n,
store,
router,
render: h => h(App)
}).$mount('#app')
})
+37 -16
View File
@@ -1,6 +1,8 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import TimeAgo from 'javascript-time-ago'
import store from '@/store'
import ENTranslations from '@/translations/en.json'
Vue.use(VueI18n)
@@ -15,6 +17,10 @@ export const i18n = new VueI18n({
messages
})
const TIME_AGO_EXCEPTIONS = {
'bn-Beng': 'bn'
}
async function syncStylesPerLanguage (locale) {
switch (locale) {
// All the latin languages
@@ -25,43 +31,43 @@ async function syncStylesPerLanguage (locale) {
case 'lt':
case 'ml':
case 'tr':
case 'bn_latn':
case 'bn-Latn':
// Don't need to import fonts because Latin fonts are always loaded
document.body.classList.remove(...document.body.classList)
document.body.classList.add('latin')
break
// Bengali script
case 'bn_beng':
// Bengali script
case 'bn-Beng':
await import('@fontsource/hind-siliguri/bengali.css')
document.body.classList.remove(...document.body.classList)
document.body.classList.add('bengali')
break
// Other languages
// NOTE: if you are a native speaker & want to see a different font, just email me or join the channel
case 'zh_Hant':
// Other languages
// NOTE: if you are a native speaker & want to see a different font, just email me or join the channel
case 'zh-Hant':
await import('@fontsource/noto-sans-tc/chinese-traditional.css')
document.body.classList.remove(...document.body.classList)
document.body.classList.add('traditional-chinese')
break
case 'zh_Hans':
case 'zh-Hans':
await import('@fontsource/noto-sans-sc/chinese-simplified.css')
document.body.classList.remove(...document.body.classList)
document.body.classList.add('simplified-chinese')
break
case 'jp':
case 'ja':
await import('@fontsource/noto-sans-jp/japanese.css')
document.body.classList.remove(...document.body.classList)
document.body.classList.add('japanese')
break
case 'kr':
case 'ko':
await import('@fontsource/noto-sans-kr/korean.css')
document.body.classList.remove(...document.body.classList)
document.body.classList.add('korean')
break
case 'cyrl':
case 'ru':
await import('@fontsource/nunito-sans/cyrillic.css')
document.body.classList.remove(...document.body.classList)
document.body.classList.add('cyrillic')
document.body.classList.add('russian')
break
}
}
@@ -71,7 +77,7 @@ export async function loadLocale (locale) {
return
}
// load locale messages with dynamic import
const messages = await import(/* webpackChunkName: "locale-[request]" */ `@/translations/${locale}.json`)
const messages = await import(/* webpackChunkName: "translations-[request]" */ `@/translations/${locale}.json`)
// set locale and locale message
i18n.setLocaleMessage(locale, messages.default)
@@ -79,9 +85,24 @@ export async function loadLocale (locale) {
return Vue.nextTick()
}
async function loadFormatting (locale) {
const tal = TIME_AGO_EXCEPTIONS[locale] || locale
const data = await import(/* webpackChunkName: "timeago-[request]" */ `javascript-time-ago/locale/${tal}.json`)
TimeAgo.addLocale(data)
const timeAgo = new TimeAgo(locale)
store.commit('i18n/updateState', {
intlLocale: locale,
timeAgo
})
}
export async function changeLocale (lang) {
await loadLocale(lang)
await syncStylesPerLanguage(lang)
await Promise.all([
loadLocale(lang),
syncStylesPerLanguage(lang),
loadFormatting(lang)
])
i18n.locale = lang
window.localStorage.setItem('LOCALE', lang)
}
@@ -92,7 +113,7 @@ function initializeLocalLocale () {
// Default language
lang = 'en'
}
changeLocale(lang).catch(e => console.error(e))
return changeLocale(lang)
}
initializeLocalLocale()
export const i18nInitialized = initializeLocalLocale()
-4
View File
@@ -111,10 +111,6 @@ export default {
})
},
numberFormat (...args) {
return LibPiped.numberFormat(...args)
},
timeFormat (...args) {
return LibPiped.timeFormat(...args)
},
+6 -10
View File
@@ -17,19 +17,19 @@
<v-card outlined color="bgTwo">
<v-card-title class="text-h5">{{ video.title }}</v-card-title>
<v-card-subtitle class="text-subtitle-1">
<v-row>
<v-col md="5" align-self="start">
{{ $tc('counts.views', video.views, { n: addCommas(video.views) }) }}
<v-row align="center">
<v-col>
{{ $tc('counts.views', video.views, { n: $store.getters['i18n/fmtNumber'](video.views) }) }}
•
{{ video.uploadDate }}
{{ $store.getters['i18n/fmtDate'](new Date(video.uploadDate)) }}
<!-- TODO make translatable -->
<span v-if="lastWatch">
•
Last watched till {{ lastWatchDurationH }}
{{ $t('misc.lastWatchedTill', { t: lastWatchDurationH }) }}
<ExpandableDate :date="lastWatch.timestamp" />
</span>
</v-col>
<v-col offset-md="4" md="3" align-self="end">
<v-col style="text-align: right">
<v-icon>mdi-thumb-up</v-icon>
<b class="ml-2">{{ addCommas(video.likes) }}</b>
<v-icon class="ml-2">mdi-thumb-down</v-icon>
@@ -222,10 +222,6 @@ export default {
window.location.href = url.href
},
numberFormat (...args) {
return LibPiped.numberFormat(...args)
},
addCommas (...args) {
return LibPiped.addCommas(...args)
},
+42
View File
@@ -0,0 +1,42 @@
export const i18nStore = {
namespaced: true,
state: () => ({
fullFormatter: null,
dateFormatter: null,
NF: null,
timeAgo: null
}),
mutations: {
updateState (state, { intlLocale, NF, timeAgo }) {
state.fullFormatter = new Intl.DateTimeFormat(intlLocale, {
dateStyle: 'full',
timeStyle: 'full'
})
state.dateFormatter = new Intl.DateTimeFormat(intlLocale, {
dateStyle: 'long'
})
state.NF = new Intl.NumberFormat(intlLocale)
state.timeAgo = timeAgo
}
},
getters: {
fmtRelative: state => time => {
return state.timeAgo.format(time)
},
fmtNumber: state => num => {
return state.NF.format(num)
},
fmtDate: state => dt => {
return state.dateFormatter.format(dt)
},
fmtDateTime: state => dt => {
return state.fullFormatter.format(dt)
}
}
}
+3 -1
View File
@@ -3,13 +3,15 @@ import Vuex from 'vuex'
import { PrefsStore, initializePrefEvents } from '@/store/prefs-store'
import { AuthenticationStore, initializeAuthEvents } from '@/store/authentication-store'
import { i18nStore } from '@/store/i18n-store'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
prefs: PrefsStore,
auth: AuthenticationStore
auth: AuthenticationStore,
i18n: i18nStore
}
})
+1 -1
View File
@@ -35,7 +35,7 @@
@include addFonts('Noto Sans KR');
}
.cyrillic {
.russian {
@include addFonts('Nunito Sans');
}
-49
View File
@@ -1,17 +1,6 @@
import DOMPurify from 'dompurify'
import TimeAgo from 'javascript-time-ago'
import en from 'javascript-time-ago/locale/en'
TimeAgo.addDefaultLocale(en)
const timeAgo = new TimeAgo('en-US')
class LibPiped {
intlDTF = new Intl.DateTimeFormat([], {
dateStyle: 'full',
timeStyle: 'full'
})
pad (num, size) {
return ('000' + num).slice(size * -1)
}
@@ -31,40 +20,6 @@ class LibPiped {
return str
}
formatFullDate (date) {
return this.intlDTF.format(date)
}
numberFormat (num) {
const digits = 2
const si = [
{
value: 1,
symbol: ''
},
{
value: 1e3,
symbol: 'K'
},
{
value: 1e6,
symbol: 'M'
},
{
value: 1e9,
symbol: 'B'
}
]
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/
let i
for (i = si.length - 1; i > 0; i--) {
if (num >= si[i].value) {
break
}
}
return (num / si[i].value).toFixed(digits).replace(rx, '$1') + si[i].symbol
}
addCommas (num) {
num = parseInt(num)
return num.toLocaleString('en-US')
@@ -74,10 +29,6 @@ class LibPiped {
return DOMPurify.sanitize(original)
}
timeAgo (time) {
return timeAgo.format(time)
}
determineVideoIdFromPath (path) {
const loc = new URL(path, 'http://localhost')
return loc.searchParams.get('v')
@@ -15,7 +15,8 @@
"trendingFetchError": "জনপ্রিয় ভিডিও খুঁজে পাওয়া যায়নি। দেখুন আপনার নির্বাচিত দেশ কে ইউটুবে সাপোর্ট করে কি না।"
},
"misc": {
"searchBarLabel": "কি সন্ধান করছেন বলুন?"
"searchBarLabel": "কি সন্ধান করছেন বলুন?",
"lastWatchedTill": "আপনি {t} পর্যন্ত দেখেছিলেন"
},
"actions": {
"subscribe": "সদস্যতা নিন",
+2 -1
View File
@@ -16,7 +16,8 @@
"trendingFetchError": "Could not fetch trending videos. Check whether your country is supported by YouTube"
},
"misc": {
"searchBarLabel": "What are you looking for?"
"searchBarLabel": "What are you looking for?",
"lastWatchedTill": "Last watched till {t}"
},
"actions": {
"subscribe": "Subscribe",