-
-
Notifications
You must be signed in to change notification settings - Fork 427
feat: change i18n configuration #245
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
Closed
Closed
Changes from 11 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
844ac96
feat: change i18n configuration
userquin 045d73d
Merge branch 'main' into feat-change-i18n-configuration
userquin 071f616
chore: prepare lunaria json files
userquin 0b7010c
chore: add fr-FR to locales
userquin de5ceb0
chore: add land and dir to html element
userquin 3c2c4f5
chore: cleanup
userquin c340d50
chore: genrate lunaria json files at lunaria/files
userquin b6373c7
chore: add lang html attr to app head to avoid html validator errors
userquin 3b5fa46
chore: cleanup
userquin ad567da
chore: cleanup
userquin 20dd656
chore: fix html validation errors
userquin c52df4f
chore: cleanup
userquin 4b5cbb8
Merge branch 'main' into feat-change-i18n-configuration
userquin f9002f2
chore: update i18n stuff for German locale
userquin 4f576e7
Merge branch 'main' into feat-change-i18n-configuration
userquin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| import type { UseTimeAgoOptions } from '@vueuse/core' | ||
|
|
||
| const formatter = Intl.NumberFormat() | ||
|
|
||
| export function formattedNumber(num: number, useFormatter: Intl.NumberFormat = formatter) { | ||
| return useFormatter.format(num) | ||
| } | ||
|
|
||
| export function useHumanReadableNumber() { | ||
| const { n, locale } = useI18n() | ||
|
|
||
| const fn = (num: number) => { | ||
| return n( | ||
| num, | ||
| num < 10000 ? 'smallCounting' : num < 1000000 ? 'kiloCounting' : 'millionCounting', | ||
| locale.value, | ||
| ) | ||
| } | ||
|
|
||
| return { | ||
| formatHumanReadableNumber: (num: MaybeRef<number>) => fn(unref(num)), | ||
| formatNumber: (num: MaybeRef<number>) => n(unref(num), 'smallCounting', locale.value), | ||
| formatPercentage: (num: MaybeRef<number>) => n(unref(num), 'percentage', locale.value), | ||
| forSR: (num: MaybeRef<number>) => unref(num) > 10000, | ||
| } | ||
| } | ||
|
|
||
| export function useFormattedDateTime( | ||
| value: MaybeRefOrGetter<string | number | Date | undefined | null>, | ||
| options: Intl.DateTimeFormatOptions = { dateStyle: 'long', timeStyle: 'medium' }, | ||
| ) { | ||
| const { locale } = useI18n() | ||
| const formatter = computed(() => Intl.DateTimeFormat(locale.value, options)) | ||
| return computed(() => { | ||
| const v = toValue(value) | ||
| return v ? formatter.value.format(new Date(v)) : '' | ||
| }) | ||
| } | ||
|
|
||
| export function useTimeAgoOptions(short = false): UseTimeAgoOptions<false> { | ||
| const { d, t, n: fnf, locale } = useI18n() | ||
| const prefix = short ? 'short_' : '' | ||
|
|
||
| const fn = (n: number, past: boolean, key: string) => { | ||
| return t(`time_ago_options.${prefix}${key}_${past ? 'past' : 'future'}`, n, { | ||
| named: { | ||
| v: fnf(n, 'smallCounting', locale.value), | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| return { | ||
| rounding: 'floor', | ||
| showSecond: !short, | ||
| updateInterval: short ? 60000 : 1000, | ||
| messages: { | ||
| justNow: t('time_ago_options.just_now'), | ||
| // just return the value | ||
| past: n => n, | ||
| // just return the value | ||
| future: n => n, | ||
| second: (n, p) => fn(n, p, 'second'), | ||
| minute: (n, p) => fn(n, p, 'minute'), | ||
| hour: (n, p) => fn(n, p, 'hour'), | ||
| day: (n, p) => fn(n, p, 'day'), | ||
| week: (n, p) => fn(n, p, 'week'), | ||
| month: (n, p) => fn(n, p, 'month'), | ||
| year: (n, p) => fn(n, p, 'year'), | ||
| invalid: '', | ||
| }, | ||
| fullDateFormatter(date) { | ||
| return d(date, short ? 'short' : 'long') | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| export function useFileSizeFormatter() { | ||
| const { locale } = useI18n() | ||
|
|
||
| const formatters = computed( | ||
| () => | ||
| [ | ||
| Intl.NumberFormat(locale.value, { | ||
| style: 'unit', | ||
| unit: 'megabyte', | ||
| unitDisplay: 'narrow', | ||
| maximumFractionDigits: 0, | ||
| }), | ||
| Intl.NumberFormat(locale.value, { | ||
| style: 'unit', | ||
| unit: 'kilobyte', | ||
| unitDisplay: 'narrow', | ||
| maximumFractionDigits: 0, | ||
| }), | ||
| ] as const, | ||
| ) | ||
|
|
||
| const megaByte = 1024 * 1024 | ||
|
|
||
| function formatFileSize(size: number) { | ||
| return size >= megaByte | ||
| ? formatters.value[0].format(size / megaByte) | ||
| : formatters.value[1].format(size / 1024) | ||
| } | ||
|
|
||
| return { formatFileSize } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import type { SchemaAugmentations } from '@unhead/schema' | ||
| import type { ActiveHeadEntry, UseHeadInput, UseHeadOptions } from '@unhead/vue' | ||
| import type { ComponentInternalInstance } from 'vue' | ||
| import { onActivated, onDeactivated, ref } from 'vue' | ||
|
|
||
| export const isHydrated = ref(false) | ||
|
|
||
| export function onHydrated(cb: () => unknown) { | ||
| watch(isHydrated, () => cb(), { immediate: isHydrated.value, once: true }) | ||
| } | ||
|
|
||
| /** | ||
| * ### Whether the current component is running in the background | ||
| * | ||
| * for handling problems caused by the keepalive function | ||
| */ | ||
| export function useDeactivated() { | ||
| const deactivated = ref(false) | ||
| onActivated(() => (deactivated.value = false)) | ||
| onDeactivated(() => (deactivated.value = true)) | ||
|
|
||
| return deactivated | ||
| } | ||
|
|
||
| /** | ||
| * ### When the component is restored from the background | ||
| * | ||
| * for handling problems caused by the keepalive function | ||
| * | ||
| * @param hook | ||
| * @param target | ||
| */ | ||
| export function onReactivated(hook: () => void, target?: ComponentInternalInstance | null): void { | ||
| const initial = ref(true) | ||
| onActivated(() => { | ||
| if (initial.value) return | ||
| hook() | ||
| }, target) | ||
| onDeactivated(() => (initial.value = false)) | ||
| } | ||
|
|
||
| export function useHydratedHead<T extends SchemaAugmentations>( | ||
| input: UseHeadInput<T>, | ||
| options?: UseHeadOptions, | ||
| ): ActiveHeadEntry<UseHeadInput<T>> | void { | ||
| if (input && typeof input === 'object' && !('value' in input)) { | ||
| const title = 'title' in input ? input.title : undefined | ||
| if (import.meta.server && title) { | ||
| input.meta = input.meta || [] | ||
| if (Array.isArray(input.meta)) { | ||
| input.meta.push({ | ||
| property: 'og:title', | ||
| content: (typeof input.title === 'function' ? input.title() : input.title) as string, | ||
| }) | ||
| } | ||
| } else if (title) { | ||
| ;(input as any).title = () => | ||
| isHydrated.value ? (typeof title === 'function' ? title() : title) : '' | ||
| } | ||
| } | ||
| return useHead( | ||
| (() => { | ||
| if (!isHydrated.value) return {} | ||
| return toValue(input) | ||
| }) as UseHeadInput<T>, | ||
| options, | ||
| ) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| export default defineNuxtPlugin(nuxtApp => { | ||
| nuxtApp.hooks.hookOnce('app:suspense:resolve', () => { | ||
| isHydrated.value = true | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import type { Locale } from '#i18n' | ||
|
|
||
| export default defineNuxtPlugin(async nuxt => { | ||
| const t = nuxt.vueApp.config.globalProperties.$t | ||
| const d = nuxt.vueApp.config.globalProperties.$d | ||
| const n = nuxt.vueApp.config.globalProperties.$n | ||
|
|
||
| nuxt.vueApp.config.globalProperties.$t = wrapI18n(t) | ||
| nuxt.vueApp.config.globalProperties.$d = wrapI18n(d) | ||
| nuxt.vueApp.config.globalProperties.$n = wrapI18n(n) | ||
|
|
||
| if (import.meta.client) { | ||
| const i18n = useNuxtApp().$i18n | ||
| const { setLocale, locales } = i18n | ||
| const { settings } = useSettings() | ||
| const lang = computed(() => settings.value.language as Locale) | ||
|
|
||
| const supportLanguages = unref(locales).map(locale => locale.code) | ||
| if (!supportLanguages.includes(lang.value)) | ||
| settings.value.language = getDefaultLanguage(supportLanguages) | ||
|
|
||
| if (lang.value !== i18n.locale.value) await setLocale(settings.value.language as Locale) | ||
|
|
||
| watch( | ||
| [lang, isHydrated], | ||
| () => { | ||
| if (isHydrated.value && lang.value !== i18n.locale.value) setLocale(lang.value) | ||
| }, | ||
| { immediate: true }, | ||
| ) | ||
| } | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import { useI18n as useOriginalI18n } from 'vue-i18n' | ||
|
|
||
| export function useI18n() { | ||
| const i18n = useOriginalI18n() | ||
|
|
||
| const { t, d, n, ...rest } = i18n | ||
|
|
||
| return { | ||
| ...rest, | ||
| t: wrapI18n(t), | ||
| d: wrapI18n(d), | ||
| n: wrapI18n(n), | ||
| } satisfies ReturnType<typeof useOriginalI18n> | ||
| } | ||
|
|
||
| export function wrapI18n<T extends (...args: any[]) => any>(t: T): T { | ||
| return <T>((...args: any[]) => { | ||
| return import.meta.server ? t(...args) : isHydrated.value ? t(...args) : '' | ||
| }) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| export function matchLanguages( | ||
| languages: string[], | ||
| acceptLanguages: readonly string[], | ||
| ): string | null { | ||
| { | ||
| // const lang = acceptLanguages.map(userLang => languages.find(lang => lang.startsWith(userLang))).filter(v => !!v)[0] | ||
| // TODO: Support es-419, remove this code if we include spanish country variants | ||
| const lang = acceptLanguages | ||
| .map(userLang => | ||
| languages.find(currentLang => { | ||
| if (currentLang === userLang) return currentLang | ||
|
|
||
| // Edge browser: case for ca-valencia | ||
| if (currentLang === 'ca-valencia' && userLang === 'ca-Es-VALENCIA') return currentLang | ||
|
|
||
| if (userLang.startsWith('es-') && userLang !== 'es-ES' && currentLang === 'es-419') | ||
| return currentLang | ||
|
|
||
| return currentLang.startsWith(userLang) ? currentLang : undefined | ||
| }), | ||
| ) | ||
| .find(v => !!v) | ||
| if (lang) return lang | ||
| } | ||
|
|
||
| const lang = acceptLanguages | ||
| .map(userLang => { | ||
| userLang = userLang.split('-')[0]! | ||
| return languages.find(lang => lang.startsWith(userLang)) | ||
| }) | ||
| .find(v => !!v) | ||
| if (lang) return lang | ||
|
|
||
| return null | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
argg, undo this