forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1import type {
2 DateTimeFormats,
3 NumberFormats,
4 PluralizationRule,
5 PluralizationRules,
6} from '@intlify/core-base'
7import type { LocaleObject } from '@nuxtjs/i18n'
8
9interface LocaleObjectData extends LocaleObject {
10 numberFormats?: NumberFormats
11 dateTimeFormats?: DateTimeFormats
12 pluralRule?: PluralizationRule
13}
14
15export const countryLocaleVariants: Record<string, (LocaleObjectData & { country?: boolean })[]> = {
16 ar: [
17 // ar.json contains ar-EG translations
18 // { code: 'ar-DZ', name: 'Arabic (Algeria)' },
19 // { code: 'ar-BH', name: 'Arabic (Bahrain)' },
20 { country: true, code: 'ar-EG', name: 'العربية' },
21 // { code: 'ar-EG', name: 'Arabic (Egypt)' },
22 // { code: 'ar-IQ', name: 'Arabic (Iraq)' },
23 // { code: 'ar-JO', name: 'Arabic (Jordan)' },
24 // { code: 'ar-KW', name: 'Arabic (Kuwait)' },
25 // { code: 'ar-LB', name: 'Arabic (Lebanon)' },
26 // { code: 'ar-LY', name: 'Arabic (Libya)' },
27 // { code: 'ar-MA', name: 'Arabic (Morocco)' },
28 // { code: 'ar-OM', name: 'Arabic (Oman)' },
29 // { code: 'ar-QA', name: 'Arabic (Qatar)' },
30 // { code: 'ar-SA', name: 'Arabic (Saudi Arabia)' },
31 // { code: 'ar-SY', name: 'Arabic (Syria)' },
32 // { code: 'ar-TN', name: 'Arabic (Tunisia)' },
33 // { code: 'ar-AE', name: 'Arabic (U.A.E.)' },
34 // { code: 'ar-YE', name: 'Arabic (Yemen)' },
35 ],
36 en: [
37 // en.json contains en-US translations
38 { country: true, code: 'en-US', name: 'English (US)' },
39 // { code: 'en-CA', name: 'English (Canada)' },
40 { code: 'en-GB', name: 'English (UK)' },
41 ],
42 /*ca: [
43 // ca.json contains ca-ES translations
44 // { code: 'ca-AD', name: 'Català (Andorra)' },
45 { country: true, code: 'ca-ES', name: 'Català (Espanya)' },
46 { code: 'ca-valencia', name: 'Català (valencià)' },
47 // { code: 'ca-FR', name: 'Català (França)' },
48 // { code: 'ca-IT', name: 'Català (Itàlia)' },
49 ],*/
50 es: [
51 // es.json contains es-ES translations
52 // { code: 'es-AR', name: 'Español (Argentina)' },
53 // { code: 'es-BO', name: 'Español (Bolivia)' },
54 // { code: 'es-CL', name: 'Español (Chile)' },
55 // { code: 'es-CO', name: 'Español (Colombia)' },
56 // { code: 'es-CR', name: 'Español (Costa Rica)' },
57 // { code: 'es-DO', name: 'Español (República Dominicana)' },
58 // { code: 'es-EC', name: 'Español (Ecuador)' },
59 { country: true, code: 'es-ES', name: 'Español (España)' },
60 // TODO: Support es-419, if we include spanish country variants remove also fix on utils/language.ts module
61 { code: 'es-419', name: 'Español (Latinoamérica)' },
62 // { code: 'es-GT', name: 'Español (Guatemala)' },
63 // { code: 'es-HN', name: 'Español (Honduras)' },
64 // { code: 'es-MX', name: 'Español (México)' },
65 // { code: 'es-NI', name: 'Español (Nicaragua)' },
66 // { code: 'es-PA', name: 'Español (Panamá)' },
67 // { code: 'es-PE', name: 'Español (Perú)' },
68 // { code: 'es-PR', name: 'Español (Puerto Rico)' },
69 // { code: 'es-SV', name: 'Español (El Salvador)' },
70 // { code: 'es-US', name: 'Español (Estados Unidos)' },
71 // { code: 'es-UY', name: 'Español (Uruguay)' },
72 // { code: 'es-VE', name: 'Español (Venezuela)' },
73 ],
74 /*pt: [
75 // pt.json contains pt-PT translations
76 { country: true, code: 'pt-PT', name: 'Português (Portugal)' },
77 { code: 'pt-BR', name: 'Português (Brasil)' },
78 ],*/
79}
80
81function createPluralRule(locale: string, mapping: Record<string, number>) {
82 return (choice: number, choicesLength: number) => {
83 const name = new Intl.PluralRules(locale).select(choice)
84 const plural = mapping[name] || 0
85
86 // In case translation doesn't have all plural forms, use the last available form
87 if (plural > choicesLength - 1) {
88 if (import.meta.dev) {
89 // oxlint-disable-next-line no-console -- warn logging
90 console.warn(
91 `Plural form index ${plural} for choice ${choice} exceeds available forms ${choicesLength} for locale ${locale}.`,
92 )
93 }
94 return choicesLength - 1
95 }
96
97 return plural
98 }
99}
100
101const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { code: string }))[] = [
102 {
103 code: 'en',
104 file: 'en.json',
105 name: 'English',
106 },
107 {
108 code: 'ar',
109 file: 'ar.json',
110 name: 'العربية',
111 dir: 'rtl',
112 pluralRule: createPluralRule('ar-EG', { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }),
113 },
114 {
115 code: 'az-AZ',
116 file: 'az-AZ.json',
117 name: 'Azərbaycanca',
118 },
119 {
120 code: 'bn-IN',
121 file: 'bn-IN.json',
122 name: 'বাংলা',
123 },
124 {
125 code: 'bg-BG',
126 file: 'bg-BG.json',
127 name: 'Български',
128 pluralRule: createPluralRule('bg-BG', { zero: 1, one: 0, two: 1, few: 1, many: 1, other: 1 }),
129 },
130 /*{
131 code: 'ckb',
132 file: 'ckb.json',
133 name: 'کوردیی ناوەندی',
134 dir: 'rtl',
135 pluralRule: (choice: number) => {
136 const name = new Intl.PluralRules('ckb').select(choice)
137 return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
138 },
139 },
140 {
141 code: 'fa-IR',
142 file: 'fa-IR.json',
143 name: 'فارسی',
144 dir: 'rtl',
145 pluralRule: (choice: number) => {
146 const name = new Intl.PluralRules('fa-IR').select(choice)
147 return { zero: 0, one: 1, two: 2, few: 3, many: 4, other: 5 }[name]
148 },
149 },
150 {
151 code: 'ca',
152 file: 'ca.json',
153 name: 'Català',
154 },
155 {
156 code: 'el-GR',
157 file: 'el-GR.json',
158 name: 'Ελληνικά',
159 },*/
160 {
161 code: 'de-DE',
162 file: 'de-DE.json',
163 name: 'Deutsch',
164 },
165 {
166 code: 'hi-IN',
167 file: 'hi-IN.json',
168 name: 'हिंदी',
169 },
170 {
171 code: 'te-IN',
172 file: 'te-IN.json',
173 name: 'తెలుగు',
174 },
175 {
176 code: 'mr-IN',
177 file: 'mr-IN.json',
178 name: 'मराठी',
179 },
180 {
181 code: 'hu-HU',
182 file: 'hu-HU.json',
183 name: 'Magyar',
184 pluralRule: createPluralRule('hu-HU', { zero: 0, one: 0, two: 1, few: 1, many: 1, other: 1 }),
185 },
186 {
187 code: 'zh-CN',
188 file: 'zh-CN.json',
189 name: '简体中文',
190 },
191 {
192 code: 'zh-TW',
193 file: 'zh-TW.json',
194 name: '繁體中文',
195 },
196 {
197 code: 'ja-JP',
198 file: 'ja-JP.json',
199 name: '日本語',
200 },
201 {
202 code: 'ne-NP',
203 file: 'ne-NP.json',
204 name: 'नेपाली',
205 },
206 /*{
207 code: 'nl-NL',
208 file: 'nl-NL.json',
209 name: 'Nederlands',
210 },*/
211 {
212 code: 'es',
213 file: 'es.json',
214 name: 'Español',
215 },
216 /*{
217 code: 'eu-ES',
218 file: 'eu-ES.json',
219 name: 'Euskara',
220 },*/
221 {
222 code: 'fr-FR',
223 file: 'fr-FR.json',
224 name: 'Français',
225 },
226 {
227 code: 'ru-RU',
228 file: 'ru-RU.json',
229 name: 'Русский',
230 pluralRule: createPluralRule('ru-RU', { zero: 2, one: 0, two: 1, few: 1, many: 2, other: 3 }),
231 },
232 {
233 code: 'uk-UA',
234 file: 'uk-UA.json',
235 name: 'Українська',
236 pluralRule: createPluralRule('uk-UA', { zero: 0, one: 1, two: 0, few: 2, many: 3, other: 4 }),
237 },
238 /*{
239 code: 'ru-RU',
240 file: 'ru-RU.json',
241 name: 'Русский',
242 pluralRule: (choice: number) => {
243 const name = new Intl.PluralRules('ru-RU').select(choice)
244 return { zero: 2 /!* not used *!/, one: 0, two: 1 /!* not used *!/, few: 1, many: 2, other: 3 }[name]
245 },
246 },*/
247 {
248 code: 'cs-CZ',
249 file: 'cs-CZ.json',
250 name: 'Čeština',
251 pluralRule: createPluralRule('cs-CZ', { zero: 2, one: 0, two: 1, few: 1, many: 2, other: 2 }),
252 } /*
253 {
254 code: 'pl-PL',
255 file: 'pl-PL.json',
256 name: 'Polski',
257 pluralRule: (choice: number) => {
258 if (choice === 0)
259 return 0
260
261 const name = new Intl.PluralRules('pl-PL').select(choice)
262 return { zero: 0, one: 1, two: 0 /!* not used *!/, few: 2, many: 3, other: 4 }[name]
263 },
264 },
265 {
266 code: 'pt',
267 file: 'pt.json',
268 name: 'Português',
269 },
270 {
271 code: 'tr-TR',
272 file: 'tr-TR.json',
273 name: 'Türkçe',
274 },
275 {
276 code: 'id-ID',
277 file: 'id-ID.json',
278 name: 'Indonesia',
279 },
280 {
281 code: 'fi',
282 file: 'fi.json',
283 name: 'Suomi',
284 },
285 {
286 code: 'gl-ES',
287 file: 'gl-ES.json',
288 name: 'Galego',
289 },
290 {
291 code: 'ko-KR',
292 file: 'ko-KR.json',
293 name: '한국어',
294 },*/,
295 {
296 code: 'id-ID',
297 file: 'id-ID.json',
298 name: 'Indonesia',
299 },
300 {
301 code: 'it-IT',
302 file: 'it-IT.json',
303 name: 'Italiano',
304 },
305 {
306 code: 'pl-PL',
307 file: 'pl-PL.json',
308 name: 'Polski',
309 pluralRule: createPluralRule('pl-PL', { zero: 0, one: 1, two: 0, few: 2, many: 3, other: 4 }),
310 },
311 {
312 code: 'pt-BR',
313 file: 'pt-BR.json',
314 name: 'Português (Brasil)',
315 },
316 /*{
317 code: 'sv',
318 file: 'sv.json',
319 name: 'Svenska',
320 },
321 {
322 code: 'th-TH',
323 file: 'th-TH.json',
324 name: 'ไทย',
325 },
326 {
327 code: 'tl-PH',
328 file: 'tl-PH.json',
329 name: 'Tagalog',
330 },
331 {
332 code: 'vi-VN',
333 file: 'vi-VN.json',
334 name: 'Tiếng Việt',
335 },
336 {
337 code: 'cy',
338 file: 'cy.json',
339 name: 'Cymraeg',
340 },*/
341 {
342 code: 'nb-NO',
343 file: 'nb-NO.json',
344 name: 'Norsk (Bokmål)',
345 },
346]
347
348const lunariaJSONFiles: Record<string, string> = {}
349
350function buildLocales() {
351 const useLocales = Object.values(locales).reduce((acc, data) => {
352 const locales = countryLocaleVariants[data.code]
353 if (locales) {
354 locales.forEach(l => {
355 const entry: LocaleObjectData = {
356 ...data,
357 code: l.code,
358 name: l.name,
359 files: [data.file as string, `${l.code}.json`],
360 }
361 lunariaJSONFiles[l.code] = l.country ? (data.file as string) : `${l.code}.json`
362 delete entry.file
363 acc.push(entry)
364 })
365 } else {
366 lunariaJSONFiles[data.code] = data.file as string
367 acc.push(data as LocaleObjectData)
368 }
369 return acc
370 }, [] as LocaleObjectData[])
371
372 return useLocales.sort((a, b) => a.code.localeCompare(b.code))
373}
374
375export const currentLocales = buildLocales()
376
377export { lunariaJSONFiles }
378
379export const datetimeFormats = Object.values(currentLocales).reduce((acc, data) => {
380 const dateTimeFormats = data.dateTimeFormats
381 if (dateTimeFormats) {
382 acc[data.code] = { ...dateTimeFormats }
383 delete data.dateTimeFormats
384 } else {
385 acc[data.code] = {
386 shortDate: {
387 dateStyle: 'short',
388 },
389 short: {
390 dateStyle: 'short',
391 timeStyle: 'short',
392 },
393 long: {
394 dateStyle: 'long',
395 timeStyle: 'medium',
396 },
397 }
398 }
399
400 return acc
401}, {} as DateTimeFormats)
402
403export const numberFormats = Object.values(currentLocales).reduce((acc, data) => {
404 const numberFormats = data.numberFormats
405 if (numberFormats) {
406 acc[data.code] = { ...numberFormats }
407 delete data.numberFormats
408 } else {
409 acc[data.code] = {
410 percentage: {
411 style: 'percent',
412 maximumFractionDigits: 1,
413 },
414 smallCounting: {
415 style: 'decimal',
416 maximumFractionDigits: 0,
417 },
418 kiloCounting: {
419 notation: 'compact',
420 compactDisplay: 'short',
421 maximumFractionDigits: 1,
422 },
423 millionCounting: {
424 notation: 'compact',
425 compactDisplay: 'short',
426 maximumFractionDigits: 2,
427 },
428 }
429 }
430
431 return acc
432}, {} as NumberFormats)
433
434export const pluralRules = Object.values(currentLocales).reduce((acc, data) => {
435 const pluralRule = data.pluralRule
436 if (pluralRule) {
437 acc[data.code] = pluralRule
438 delete data.pluralRule
439 }
440
441 return acc
442}, {} as PluralizationRules)