Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 9 additions & 2 deletions app/pages/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ const canGoBack = useCanGoBack()
const { settings } = useSettings()
const { locale, locales, setLocale: setNuxti18nLocale } = useI18n()
const colorMode = useColorMode()
const { currentLocaleStatus, isSourceLocale } = useI18nStatus()
const { currentLocaleStatus, isSourceLocale, getLocaleStatus } = useI18nStatus()

const localeItems = computed(() =>
locales.value.map(loc => ({
label: formatLocaleLabel(loc.name ?? '', getLocaleStatus(loc.code)),
value: loc.code,
})),
Comment on lines +9 to +13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the settings.vue file around the mentioned lines
cat -n app/pages/settings.vue | head -50

Repository: npmx-dev/npmx.dev

Length of output: 1844


🏁 Script executed:

# Let's also search for locale-related data/setup to understand the structure
rg -A 5 "locales\.value" app/pages/settings.vue | head -30

Repository: npmx-dev/npmx.dev

Length of output: 194


🏁 Script executed:

# Check the formatLocaleLabel function to understand how it handles empty strings
rg -B 2 -A 5 "formatLocaleLabel" app/pages/settings.vue

Repository: npmx-dev/npmx.dev

Length of output: 307


🏁 Script executed:

# Search for locale data source definition
rg -B 3 -A 8 "const locales" app/pages/settings.vue

Repository: npmx-dev/npmx.dev

Length of output: 43


🏁 Script executed:

# Find where useI18n is defined (likely a composable)
rg -l "useI18n|export.*useI18n" --type ts --type js

Repository: npmx-dev/npmx.dev

Length of output: 677


🏁 Script executed:

# Search for formatLocaleLabel function
rg -B 2 -A 10 "function formatLocaleLabel|const formatLocaleLabel|export.*formatLocaleLabel"

Repository: npmx-dev/npmx.dev

Length of output: 560


🏁 Script executed:

# Search for locale configuration/initialization
rg -B 3 -A 8 "locales.*=" --type ts --type js | head -50

Repository: npmx-dev/npmx.dev

Length of output: 2797


🏁 Script executed:

# Check if there's i18n configuration file
fd -e "ts|js" -i "i18n|locale" | grep -E "(config|setup|composable)" | head -20

Repository: npmx-dev/npmx.dev

Length of output: 43


🏁 Script executed:

# Check useI18nStatus composable
cat -n app/composables/useI18nStatus.ts

Repository: npmx-dev/npmx.dev

Length of output: 2814


🏁 Script executed:

# Search for where locales.value comes from in useI18n hook
rg -B 5 -A 10 "locales\s*=" app/ | grep -E "(const|let|var|locales)" | head -20

Repository: npmx-dev/npmx.dev

Length of output: 43


🏁 Script executed:

# Check how useI18n is imported and if it's from `@nuxtjs/i18n`
rg "from.*i18n|import.*useI18n" app/ --type ts --type vue

Repository: npmx-dev/npmx.dev

Length of output: 88


🏁 Script executed:

# Search for useI18n imports and usage (without problematic -t flag)
rg "useI18n|@nuxtjs/i18n" app/ --include="*.ts" --include="*.vue" -B 1 -A 1 | head -30

Repository: npmx-dev/npmx.dev

Length of output: 502


🏁 Script executed:

# Look for nuxt configuration
cat -n nuxt.config.ts 2>/dev/null || cat -n nuxt.config.js 2>/dev/null || fd -e "ts|js" -i "nuxt.config"

Repository: npmx-dev/npmx.dev

Length of output: 10479


🏁 Script executed:

# Check how locales are defined in i18n config
rg -B 5 -A 10 "i18n.*config|locales.*:" --include="*.ts" --include="*.js" | head -50

Repository: npmx-dev/npmx.dev

Length of output: 502


🏁 Script executed:

# Verify formatLocaleLabel with empty string
cat -n app/utils/locale-label.ts

Repository: npmx-dev/npmx.dev

Length of output: 572


🏁 Script executed:

# Check the i18n config file to see currentLocales structure
cat -n config/i18n.ts

Repository: npmx-dev/npmx.dev

Length of output: 14333


🏁 Script executed:

# Also search for currentLocales definition
rg "currentLocales|export.*locales" config/ -B 2 -A 8

Repository: npmx-dev/npmx.dev

Length of output: 1610


Use locale code as fallback when name is missing.
If a locale lacks name, the current empty string fallback results in a blank label (or just "(x%)"). Use the locale code as fallback for better UX.

Suggested change
const localeItems = computed(() =>
  locales.value.map(loc => ({
-   label: formatLocaleLabel(loc.name ?? '', getLocaleStatus(loc.code)),
+   label: formatLocaleLabel(loc.name ?? loc.code, getLocaleStatus(loc.code)),
    value: loc.code,
  })),
)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const localeItems = computed(() =>
locales.value.map(loc => ({
label: formatLocaleLabel(loc.name ?? '', getLocaleStatus(loc.code)),
value: loc.code,
})),
const localeItems = computed(() =>
locales.value.map(loc => ({
label: formatLocaleLabel(loc.name ?? loc.code, getLocaleStatus(loc.code)),
value: loc.code,
})),

)

// Escape to go back (but not when focused on form elements or modal is open)
onKeyStroke(
Expand Down Expand Up @@ -219,7 +226,7 @@ const setLocale: typeof setNuxti18nLocale = locale => {
<ClientOnly>
<SelectField
id="language-select"
:items="locales.map(loc => ({ label: loc.name ?? '', value: loc.code }))"
:items="localeItems"
v-model="locale"
@update:modelValue="setLocale($event as typeof locale)"
block
Expand Down
12 changes: 12 additions & 0 deletions app/utils/locale-label.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { I18nLocaleStatus } from '#shared/types'

/**
* Format a locale label for the language selector, appending the completion
* percentage when the locale is not fully translated.
*/
export function formatLocaleLabel(name: string, localeStatus: I18nLocaleStatus | null): string {
if (localeStatus && localeStatus.percentComplete < 100) {
return `${name} (${localeStatus.percentComplete}%)`
}
return name
}
34 changes: 34 additions & 0 deletions test/unit/app/utils/locale-label.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, it, expect } from 'vitest'
import { formatLocaleLabel } from '../../../../app/utils/locale-label'
import type { I18nLocaleStatus } from '#shared/types'

function makeStatus(percentComplete: number): I18nLocaleStatus {
return {
lang: 'fr-FR',
label: 'Français',
totalKeys: 200,
completedKeys: Math.round((percentComplete / 100) * 200),
missingKeys: [],
percentComplete,
githubEditUrl: '',
githubHistoryUrl: '',
}
}

describe('formatLocaleLabel', () => {
it('appends percentage when locale is partially translated', () => {
expect(formatLocaleLabel('Français', makeStatus(85))).toBe('Français (85%)')
})

it('appends percentage when locale is 0% translated', () => {
expect(formatLocaleLabel('العربية', makeStatus(0))).toBe('العربية (0%)')
})

it('does not append percentage when locale is 100% complete', () => {
expect(formatLocaleLabel('English (US)', makeStatus(100))).toBe('English (US)')
})

it('returns plain name when locale status is null', () => {
expect(formatLocaleLabel('English', null)).toBe('English')
})
})
Loading