Skip to content

Commit 98508a5

Browse files
committed
Merge branch 'main' into i18n/az
2 parents 4b1c248 + 5c973cd commit 98508a5

11 files changed

Lines changed: 70 additions & 41 deletions

File tree

CONTRIBUTING.md

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -256,31 +256,46 @@ The [config/i18n.ts](./config/i18n.ts) configuration file will be used to regist
256256
- `locales` object will be used to link the supported locales (country and single one)
257257
- `buildLocales` function will build the target locales
258258

259-
To register a new locale:
259+
To add a new locale:
260260

261-
- for a single country, your JSON file should include the language and the country in the name (for example, `pl-PL.json`) and register the info at `locales` object
262-
- for multiple country variants, you need to add the default language JSON file (for example for Spanish, `es.json`) and one of the country variants (for example for Spanish for Spain, `es-ES.json`); register the language at `countryLocaleVariants` object adding the country variants with the JSON country file and register the language at `locales` object using the language JSON file (check how we register `es`, `es-ES` and `es-419` in [config/i18n.ts](./config/i18n.ts))
261+
1. Create a new JSON file in [`i18n/locales/`](./i18n/locales) with the locale code as the filename (e.g., `uk-UA.json`, `de-DE.json`)
262+
2. Copy [`en.json`](./i18n/locales/en.json) and translate the strings
263+
3. Add the locale to the `locales` array in [config/i18n.ts](./config/i18n.ts):
263264

264-
The country file should contain will contain only the translations that differ from the language JSON file, Vue I18n will merge the messages for us.
265+
```typescript
266+
{
267+
code: 'uk-UA', // Must match the filename (without .json)
268+
file: 'uk-UA.json',
269+
name: 'Українська', // Native name of the language
270+
},
271+
```
265272

266-
To add a new locale:
273+
4. Copy your translation file to `lunaria/files/` for translation tracking:
274+
275+
```bash
276+
cp i18n/locales/uk-UA.json lunaria/files/uk-UA.json
277+
```
267278

268-
1. Add a new file at [locales](./i18n/locales) folder with the language code as the filename.
269-
2. Copy [en](./i18n/locales/en.json) and translate the strings
270-
3. Add the language to the `locales` array in [config/i18n.ts](./config/i18n.ts), below `en` and `ar`:
271-
- If your language has multiple country variants, add the generic one for language only (only if there are a lot of common entries, you can always add it as a new one)
272-
- Add all country variants in [country variants object](./config/i18n.ts)
273-
- Add all country variants files with empty `messages` object: `{}`
274-
- Translate the strings in the generic language file
275-
- Later, when anyone wants to add the corresponding translations for the country variant, just override any entry in the corresponding file: you can see an example with `es` variants.
276-
- If the generic language already exists:
277-
- If the translation doesn't differ from the generic language, then add the corresponding translations in the corresponding file
278-
- If the translation differs from the generic language, then add the corresponding translations in the corresponding file and remove it from the country variants entry
279-
4. If the language is `right-to-left`, add `dir` option with `rtl` value, for example, for [ar](./config/i18n.ts)
280-
5. If the language requires special pluralization rules, add `pluralRule` callback option, for example, for [ar](./config/i18n.ts)
279+
> [!IMPORTANT]
280+
> This file must be committed. Lunaria uses git history to track translation progress, so the build will fail if this file is missing.
281+
282+
5. If the language is `right-to-left`, add `dir: 'rtl'` (see `ar-EG` in config for example)
283+
6. If the language requires special pluralization rules, add a `pluralRule` callback (see `ar-EG` or `ru-RU` in config for examples)
281284

282285
Check [Pluralization rule callback](https://vue-i18n.intlify.dev/guide/essentials/pluralization.html#custom-pluralization) for more info.
283286

287+
#### Country variants (advanced)
288+
289+
Most languages only need a single locale file. Country variants are only needed when you want to support regional differences (e.g., `es-ES` for Spain vs `es-419` for Latin America).
290+
291+
If you need country variants:
292+
293+
1. Create a base language file (e.g., `es.json`) with all translations
294+
2. Create country variant files (e.g., `es-ES.json`, `es-419.json`) with only the differing translations
295+
3. Register the base language in `locales` and add variants to `countryLocaleVariants`
296+
297+
See how `es`, `es-ES`, and `es-419` are configured in [config/i18n.ts](./config/i18n.ts) for a complete example.
298+
284299
### Adding translations
285300

286301
1. Add your translation key to `i18n/locales/en.json` first (American English is the source of truth)

app/components/PackageDeprecatedTree.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const isExpanded = shallowRef(false)
1515
const showAll = shallowRef(false)
1616
1717
const hasDeprecated = computed(
18-
() => analysisData.value && analysisData.value.deprecatedPackages.length > 0,
18+
() => analysisData.value?.deprecatedPackages && analysisData.value.deprecatedPackages.length > 0,
1919
)
2020
2121
// Banner color - purple for deprecated

app/pages/settings.vue

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ const { locale, locales, setLocale } = useI18n()
55
const colorMode = useColorMode()
66
const { currentLocaleStatus, isSourceLocale } = useI18nStatus()
77
8-
const availableLocales = computed(() =>
9-
locales.value.map(l => (typeof l === 'string' ? { code: l, name: l } : l)),
10-
)
11-
128
// Escape to go back (but not when focused on form elements)
139
onKeyStroke('Escape', e => {
1410
const target = e.target as HTMLElement
@@ -211,7 +207,7 @@ defineOgImageComponent('Default', {
211207
class="w-full sm:w-auto min-w-48 bg-bg border border-border rounded-md px-3 py-2 text-sm text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 cursor-pointer"
212208
@change="setLocale(($event.target as HTMLSelectElement).value as typeof locale)"
213209
>
214-
<option v-for="loc in availableLocales" :key="loc.code" :value="loc.code">
210+
<option v-for="loc in locales" :key="loc.code" :value="loc.code" :lang="loc.code">
215211
{{ loc.name }}
216212
</option>
217213
</select>

config/i18n.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,14 @@ export const countryLocaleVariants: Record<string, (LocaleObjectData & { country
7878
],*/
7979
}
8080

81-
const locales: (Omit<LocaleObjectData, 'code'> & { code: string })[] = [
81+
const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { code: string }))[] = [
8282
{
8383
code: 'en',
8484
file: 'en.json',
8585
name: 'English',
8686
},
8787
{
88-
code: 'ar-EG',
88+
code: 'ar',
8989
file: 'ar.json',
9090
name: 'العربية',
9191
dir: 'rtl',
@@ -108,7 +108,7 @@ const locales: (Omit<LocaleObjectData, 'code'> & { code: string })[] = [
108108
const name = new Intl.PluralRules('ckb').select(choice)
109109
return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
110110
},
111-
} satisfies LocaleObjectData,
111+
},
112112
{
113113
code: 'fa-IR',
114114
file: 'fa-IR.json',
@@ -118,7 +118,7 @@ const locales: (Omit<LocaleObjectData, 'code'> & { code: string })[] = [
118118
const name = new Intl.PluralRules('fa-IR').select(choice)
119119
return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
120120
},
121-
} satisfies LocaleObjectData,
121+
},
122122
{
123123
code: 'ca',
124124
file: 'ca.json',
@@ -182,7 +182,7 @@ const locales: (Omit<LocaleObjectData, 'code'> & { code: string })[] = [
182182
const name = new Intl.PluralRules('ru-RU').select(choice)
183183
return { zero: 2, one: 0, two: 1, few: 1, many: 2, other: 3 }[name]
184184
},
185-
} satisfies LocaleObjectData,
185+
},
186186
/*{
187187
code: 'ru-RU',
188188
file: 'ru-RU.json',
@@ -283,6 +283,8 @@ const locales: (Omit<LocaleObjectData, 'code'> & { code: string })[] = [
283283
},*/
284284
]
285285

286+
const lunariaJSONFiles: Record<string, string> = {}
287+
286288
function buildLocales() {
287289
const useLocales = Object.values(locales).reduce((acc, data) => {
288290
const locales = countryLocaleVariants[data.code]
@@ -294,10 +296,12 @@ function buildLocales() {
294296
name: l.name,
295297
files: [data.file as string, `${l.code}.json`],
296298
}
299+
lunariaJSONFiles[l.code] = l.country ? (data.file as string) : `${l.code}.json`
297300
delete entry.file
298301
acc.push(entry)
299302
})
300303
} else {
304+
lunariaJSONFiles[data.code] = data.file as string
301305
acc.push(data as LocaleObjectData)
302306
}
303307
return acc
@@ -308,6 +312,8 @@ function buildLocales() {
308312

309313
export const currentLocales = buildLocales()
310314

315+
export { lunariaJSONFiles }
316+
311317
export const datetimeFormats = Object.values(currentLocales).reduce((acc, data) => {
312318
const dateTimeFormats = data.dateTimeFormats
313319
if (dateTimeFormats) {

docs/content/index.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ seo:
44
description: A fast, modern browser for the npm registry
55
---
66

7-
## ::u-page-hero
7+
<!-- prettier-ignore-start -->
88

9+
::u-page-hero
10+
---
911
title: npmx.dev
1012
description: A fast, modern browser for the npm registry. Speed first, URL compatible, and simple.
1113
links:
12-
1314
- label: Get Started
1415
to: /getting-started/introduction
1516
color: neutral
@@ -22,11 +23,11 @@ links:
2223
size: xl
2324
icon: i-simple-icons-github
2425
variant: outline
25-
2626
---
27-
2827
::
2928

29+
<!-- prettier-ignore-end -->
30+
3031
::u-page-section{title="What you can do"}
3132
#features
3233
:::u-page-feature{icon="i-lucide-search" to="/guide/features" title="Search packages" description="Fast package search with instant results, infinite scroll, and keyboard navigation."}

lunaria/files/en-US.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@
329329
"size": "Size",
330330
"deps": "Deps",
331331
"updated": "Updated",
332-
"install": "Install",
332+
"get_started": "Get started",
333333
"readme": "Readme",
334334
"maintainers": "Maintainers",
335335
"keywords": "Keywords",

lunaria/lunaria.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createLunaria } from '@lunariajs/core'
22
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
33
import { Page } from './components.ts'
4-
import { prepareJsonFiles } from './prepare-json-files.ts'
4+
import { lunariaJSONFiles, prepareJsonFiles } from './prepare-json-files.ts'
55
import type { I18nStatus } from '../shared/types/i18n-status.ts'
66

77
await prepareJsonFiles()
@@ -61,7 +61,7 @@ const jsonStatus: I18nStatus = {
6161
}
6262

6363
const completedKeys = totalKeys - missingKeys.length
64-
const localeFilePath = `i18n/locales/${locale.lang}.json`
64+
const localeFilePath = `i18n/locales/${lunariaJSONFiles[locale.lang]!}.json`
6565

6666
return {
6767
lang: locale.lang,

lunaria/prepare-json-files.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ import type { Locale } from '@lunariajs/core'
22
import type { LocaleObject } from '@nuxtjs/i18n'
33
import * as path from 'node:path'
44
import * as fs from 'node:fs/promises'
5-
import { currentLocales } from '../config/i18n.ts'
5+
import { currentLocales, lunariaJSONFiles } from '../config/i18n.ts'
66
import { deepCopy } from '@intlify/shared'
77

88
const destFolder = path.resolve('lunaria/files')
99
const localesFolder = path.resolve('i18n/locales')
1010

1111
const defaultLocale = currentLocales.find(l => l.code === 'en-US')!
1212
/** @public */
13+
export { lunariaJSONFiles }
14+
/** @public */
1315
export const sourceLocale = {
1416
label: defaultLocale.name,
1517
lang: defaultLocale.code,

server/api/registry/file/[...pkg].get.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ERROR_PACKAGE_VERSION_AND_FILE_FAILED,
77
} from '#shared/utils/constants'
88

9-
const CACHE_VERSION = 2
9+
const CACHE_VERSION = 3
1010

1111
// Maximum file size to fetch and highlight (500KB)
1212
const MAX_FILE_SIZE = 500 * 1024

0 commit comments

Comments
 (0)