@@ -18,6 +18,7 @@ import type {
1818 ParseTransformedExtension ,
1919 ParseUnicodeExtension ,
2020 ParseUnicodeLanguageId ,
21+ ParseUnicodeLocaleId ,
2122 ParseVariantsSubtag
2223} from './locale.ts'
2324
@@ -156,10 +157,10 @@ test('ParseVariantsSubtag', () => {
156157 * Success cases
157158 */
158159
159- // 3 chars, all digits
160- expectTypeOf < ParseVariantsSubtag < [ '123 ' ] > > ( ) . toMatchTypeOf < [ [ '123 ' ] , never , [ ] ] > ( )
161- // 3 chars, first digit and alphabets
162- expectTypeOf < ParseVariantsSubtag < [ '1ab ' ] > > ( ) . toMatchTypeOf < [ [ '1ab ' ] , never , [ ] ] > ( )
160+ // 4 chars, digit + alphanum{3} (digit alphanum{3} per LDML spec)
161+ expectTypeOf < ParseVariantsSubtag < [ '1abc ' ] > > ( ) . toMatchTypeOf < [ [ '1abc ' ] , never , [ ] ] > ( )
162+ // 4 chars, all digits ( digit + digits{3})
163+ expectTypeOf < ParseVariantsSubtag < [ '1234 ' ] > > ( ) . toMatchTypeOf < [ [ '1234 ' ] , never , [ ] ] > ( )
163164 // 5 chars, all alphabets
164165 expectTypeOf < ParseVariantsSubtag < [ 'abcde' ] > > ( ) . toMatchTypeOf < [ [ 'abcde' ] , never , [ ] ] > ( )
165166 // 7 chars, alphabets and digits
@@ -175,15 +176,19 @@ test('ParseVariantsSubtag', () => {
175176 expectTypeOf < ParseVariantsSubtag < [ '1' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ '1' ] ] > ( )
176177 // range 2
177178 expectTypeOf < ParseVariantsSubtag < [ '12' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ '12' ] ] > ( )
178- // range 4
179- expectTypeOf < ParseVariantsSubtag < [ '1234 ' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ '1234 ' ] ] > ( )
179+ // range 3
180+ expectTypeOf < ParseVariantsSubtag < [ '123 ' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ '123 ' ] ] > ( )
180181 // range 9
181182 expectTypeOf < ParseVariantsSubtag < [ '123456789' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ '123456789' ] ] > ( )
182183
184+ // 3 chars, first digit and alphabets (too short for digit alphanum{3})
185+ expectTypeOf < ParseVariantsSubtag < [ '1ab' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ '1ab' ] ] > ( )
183186 // 3 chars, first alphabet and digits
184187 expectTypeOf < ParseVariantsSubtag < [ 'a12' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ 'a12' ] ] > ( )
185188 // 3 chars, all alphabets
186189 expectTypeOf < ParseVariantsSubtag < [ 'abc' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ 'abc' ] ] > ( )
190+ // 4 chars, first alphabet (not digit alphanum{3})
191+ expectTypeOf < ParseVariantsSubtag < [ 'abcd' ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ 'abcd' ] ] > ( )
187192
188193 // not string
189194 expectTypeOf < ParseVariantsSubtag < [ 1 ] > > ( ) . toMatchTypeOf < [ [ ] , never , [ 1 ] ] > ( )
@@ -203,6 +208,15 @@ test('ParseUnicodeLanguageId', () => {
203208 [ { lang : 'ja' ; script : 'Kana' ; region : 'jp' ; variants : [ 'jauer' ] } , never , [ ] ]
204209 > ( )
205210
211+ // script-only (unicode_language_id allows script subtag without language subtag)
212+ expectTypeOf < ParseUnicodeLanguageId < [ 'Kana' , 'JP' ] > > ( ) . toMatchTypeOf <
213+ [ { lang : never ; script : 'Kana' ; region : 'JP' ; variants : [ ] } , never , [ ] ]
214+ > ( )
215+ // script-only without region
216+ expectTypeOf < ParseUnicodeLanguageId < [ 'Latn' ] > > ( ) . toMatchTypeOf <
217+ [ { lang : never ; script : 'Latn' ; region : never ; variants : [ ] } , never , [ ] ]
218+ > ( )
219+
206220 /** Errors */
207221 expectTypeOf < ParseUnicodeLanguageId < 'a-ana-p-jauer-jauer' > > ( ) . toMatchTypeOf <
208222 [
@@ -327,6 +341,108 @@ test('ParsePuExtension', () => {
327341 expectTypeOf < ParsePuExtension < [ '1あ' ] > > ( ) . toMatchTypeOf < [ never , 12 , [ '1あ' ] ] > ( )
328342} )
329343
344+ test ( 'ParseUnicodeLocaleId' , ( ) => {
345+ /**
346+ * Success cases
347+ */
348+
349+ // simple language
350+ expectTypeOf < ParseUnicodeLocaleId < 'ja' > > ( ) . toMatchTypeOf <
351+ [ { lang : { lang : 'ja' ; variants : [ ] } ; extensions : [ ] } , never , [ ] ]
352+ > ( )
353+
354+ // language with region
355+ expectTypeOf < ParseUnicodeLocaleId < 'en-US' > > ( ) . toMatchTypeOf <
356+ [ { lang : { lang : 'en' ; region : 'US' ; variants : [ ] } ; extensions : [ ] } , never , [ ] ]
357+ > ( )
358+
359+ // language with script and region
360+ expectTypeOf < ParseUnicodeLocaleId < 'ja-Kana-JP' > > ( ) . toMatchTypeOf <
361+ [
362+ {
363+ lang : { lang : 'ja' ; script : 'Kana' ; region : 'JP' ; variants : [ ] }
364+ extensions : [ ]
365+ } ,
366+ never ,
367+ [ ]
368+ ]
369+ > ( )
370+
371+ // script-only
372+ expectTypeOf < ParseUnicodeLocaleId < 'Kana-JP' > > ( ) . toMatchTypeOf <
373+ [
374+ {
375+ lang : { lang : never ; script : 'Kana' ; region : 'JP' ; variants : [ ] }
376+ extensions : [ ]
377+ } ,
378+ never ,
379+ [ ]
380+ ]
381+ > ( )
382+
383+ // language with unicode extension
384+ expectTypeOf < ParseUnicodeLocaleId < 'en-US-u-co-standard' > > ( ) . toMatchTypeOf <
385+ [
386+ {
387+ lang : { lang : 'en' ; region : 'US' ; variants : [ ] }
388+ extensions : [ { type : 'u' ; keywords : [ 'co' , 'standard' ] ; attributes : [ ] } ]
389+ } ,
390+ never ,
391+ [ ]
392+ ]
393+ > ( )
394+
395+ // language with PU extension
396+ expectTypeOf < ParseUnicodeLocaleId < 'en-US-x-private' > > ( ) . toMatchTypeOf <
397+ [
398+ {
399+ lang : { lang : 'en' ; region : 'US' ; variants : [ ] }
400+ extensions : [ { type : 'x' ; value : 'private' } ]
401+ } ,
402+ never ,
403+ [ ]
404+ ]
405+ > ( )
406+
407+ // language with transformed extension
408+ expectTypeOf < ParseUnicodeLocaleId < 'en-US-t-ja-h0-hybrid' > > ( ) . toMatchTypeOf <
409+ [
410+ {
411+ lang : { lang : 'en' ; region : 'US' ; variants : [ ] }
412+ extensions : [
413+ {
414+ type : 't'
415+ lang : { lang : 'ja' ; variants : [ ] }
416+ fields : [ [ 'h0' , 'hybrid' ] ]
417+ }
418+ ]
419+ } ,
420+ never ,
421+ [ ]
422+ ]
423+ > ( )
424+
425+ // full locale with script, region, variant, and multiple extensions
426+ expectTypeOf < ParseUnicodeLocaleId < 'ja-Kana-JP-jauer-u-co-standard-x-private' > > ( ) . toMatchTypeOf <
427+ [
428+ {
429+ lang : {
430+ lang : 'ja'
431+ script : 'Kana'
432+ region : 'JP'
433+ variants : [ 'jauer' ]
434+ }
435+ extensions : [
436+ { type : 'u' ; keywords : [ 'co' , 'standard' ] ; attributes : [ ] } ,
437+ { type : 'x' ; value : 'private' }
438+ ]
439+ } ,
440+ never ,
441+ [ ]
442+ ]
443+ > ( )
444+ } )
445+
330446test ( 'ParseOtherExtension' , ( ) => {
331447 /**
332448 * Success cases
0 commit comments