@u27n/js 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.d.ts CHANGED
@@ -3,13 +3,13 @@ export interface LocaleImports {
3
3
  default: unknown[];
4
4
  }>;
5
5
  }
6
- export interface I18nOptions {
6
+ export interface U27nOptions {
7
7
  source: string;
8
8
  locales: LocaleImports;
9
9
  }
10
- export declare class I18n {
10
+ export declare class U27n {
11
11
  #private;
12
- constructor(options: I18nOptions | I18n);
12
+ constructor(options: U27nOptions | U27n);
13
13
  load(locale: string): Promise<void>;
14
14
  get locale(): string;
15
15
  set locale(value: string);
package/dist/core.js CHANGED
@@ -1,9 +1,9 @@
1
- export class I18n {
1
+ export class U27n {
2
2
  #kernel;
3
3
  #locale;
4
4
  #data;
5
5
  constructor(options) {
6
- this.#kernel = options instanceof I18n ? options.#kernel : {
6
+ this.#kernel = options instanceof U27n ? options.#kernel : {
7
7
  s: options.source,
8
8
  i: options.locales,
9
9
  p: new Map(),
@@ -0,0 +1,16 @@
1
+ import { U27n } from "./core.js";
2
+ export declare class Plural {
3
+ #private;
4
+ constructor(options?: Intl.PluralRulesOptions);
5
+ select<T>(locale: string, count: number, values: T[]): T;
6
+ }
7
+ export declare function interpolate(value: string, params: Record<string, any>): string;
8
+ export interface FormatPluralParams {
9
+ count: number;
10
+ }
11
+ export type FormatFn = <V extends string | string[], P extends (V extends string[] ? FormatPluralParams : {})>(value: V, params: P, options?: FormatOptions) => string;
12
+ export interface FormatOptions {
13
+ plural?: Plural;
14
+ }
15
+ export declare function createFormatter(u27n: U27n): FormatFn;
16
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,qBAAa,MAAM;;gBAIN,OAAO,CAAC,EAAE,IAAI,CAAC,kBAAkB;IAI7C,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC;CAexD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CA0B9E;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,QAAQ,GAAG,CACtB,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,EAC3B,CAAC,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,kBAAkB,GAAG,EAAE,CAAC,EACvD,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,MAAM,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CAYpD"}
package/dist/format.js ADDED
@@ -0,0 +1,65 @@
1
+ export class Plural {
2
+ #options;
3
+ #rules = {};
4
+ constructor(options) {
5
+ this.#options = options;
6
+ }
7
+ select(locale, count, values) {
8
+ let instance = this.#rules[locale];
9
+ if (instance === undefined) {
10
+ const rules = new Intl.PluralRules(locale, this.#options);
11
+ instance = this.#rules[locale] = {
12
+ r: rules,
13
+ f: rules.resolvedOptions().pluralCategories,
14
+ };
15
+ }
16
+ const form = instance.r.select(count);
17
+ const index = instance.f.indexOf(form);
18
+ return index < 0 || index >= values.length
19
+ ? values[values.length - 1]
20
+ : values[index];
21
+ }
22
+ }
23
+ export function interpolate(value, params) {
24
+ let output = "";
25
+ let index = 0;
26
+ while (index < value.length) {
27
+ const start = value.indexOf("{", index);
28
+ if (start < 0) {
29
+ output += value.slice(index);
30
+ break;
31
+ }
32
+ if (start > 0 && value[start - 1] === "\\") {
33
+ output += value.slice(index, start - 1) + "{";
34
+ index = start + 1;
35
+ }
36
+ else {
37
+ output += value.slice(index, start);
38
+ const end = value.indexOf("}", start + 1);
39
+ if (end < 0) {
40
+ throw new Error();
41
+ }
42
+ const key = value.slice(start + 1, end);
43
+ if (!Object.hasOwn(params, key)) {
44
+ throw new Error();
45
+ }
46
+ output += String(params[key]);
47
+ index = end + 1;
48
+ }
49
+ }
50
+ return output;
51
+ }
52
+ export function createFormatter(u27n) {
53
+ let defaultPlural;
54
+ return (value, params, options) => {
55
+ if (Array.isArray(value)) {
56
+ const plural = options?.plural ?? defaultPlural ?? (defaultPlural = new Plural());
57
+ value = plural.select(u27n.locale, params.count, value);
58
+ }
59
+ if (Object.keys(params).length > 0) {
60
+ return interpolate(value, params);
61
+ }
62
+ return value;
63
+ };
64
+ }
65
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./core.js";
2
+ export * from "./format.js";
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./core.js";
2
+ export * from "./format.js";
2
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@u27n/js",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
package/src/core.ts CHANGED
@@ -14,18 +14,18 @@ interface Kernel {
14
14
  d: Map<string, unknown[]>;
15
15
  }
16
16
 
17
- export interface I18nOptions {
17
+ export interface U27nOptions {
18
18
  source: string;
19
19
  locales: LocaleImports;
20
20
  }
21
21
 
22
- export class I18n {
22
+ export class U27n {
23
23
  #kernel: Kernel;
24
24
  #locale: string | undefined;
25
25
  #data: unknown[] | undefined;
26
26
 
27
- constructor(options: I18nOptions | I18n) {
28
- this.#kernel = options instanceof I18n ? options.#kernel : {
27
+ constructor(options: U27nOptions | U27n) {
28
+ this.#kernel = options instanceof U27n ? options.#kernel : {
29
29
  s: options.source,
30
30
  i: options.locales,
31
31
  p: new Map(),
package/src/format.ts ADDED
@@ -0,0 +1,81 @@
1
+ import { U27n } from "./core.js";
2
+
3
+ export class Plural {
4
+ #options: Intl.PluralRulesOptions | undefined;
5
+ #rules: Record<string, { r: Intl.PluralRules, f: Intl.LDMLPluralRule[] }> = {};
6
+
7
+ constructor(options?: Intl.PluralRulesOptions) {
8
+ this.#options = options;
9
+ }
10
+
11
+ select<T>(locale: string, count: number, values: T[]): T {
12
+ let instance = this.#rules[locale];
13
+ if (instance === undefined) {
14
+ const rules = new Intl.PluralRules(locale, this.#options);
15
+ instance = this.#rules[locale] = {
16
+ r: rules,
17
+ f: rules.resolvedOptions().pluralCategories,
18
+ };
19
+ }
20
+ const form = instance.r.select(count);
21
+ const index = instance.f.indexOf(form);
22
+ return index < 0 || index >= values.length
23
+ ? values[values.length - 1]
24
+ : values[index];
25
+ }
26
+ }
27
+
28
+ export function interpolate(value: string, params: Record<string, any>): string {
29
+ let output = "";
30
+ let index = 0;
31
+ while (index < value.length) {
32
+ const start = value.indexOf("{", index);
33
+ if (start < 0) {
34
+ output += value.slice(index);
35
+ break;
36
+ } if (start > 0 && value[start - 1] === "\\") {
37
+ output += value.slice(index, start - 1) + "{";
38
+ index = start + 1;
39
+ } else {
40
+ output += value.slice(index, start);
41
+ const end = value.indexOf("}", start + 1);
42
+ if (end < 0) {
43
+ throw new Error();
44
+ }
45
+ const key = value.slice(start + 1, end);
46
+ if (!Object.hasOwn(params, key)) {
47
+ throw new Error();
48
+ }
49
+ output += String(params[key]);
50
+ index = end + 1;
51
+ }
52
+ }
53
+ return output;
54
+ }
55
+
56
+ export interface FormatPluralParams {
57
+ count: number;
58
+ }
59
+
60
+ export type FormatFn = <
61
+ V extends string | string[],
62
+ P extends (V extends string[] ? FormatPluralParams : {})
63
+ >(value: V, params: P, options?: FormatOptions) => string;
64
+
65
+ export interface FormatOptions {
66
+ plural?: Plural;
67
+ }
68
+
69
+ export function createFormatter(u27n: U27n): FormatFn {
70
+ let defaultPlural: Plural | undefined;
71
+ return (value: string | string[], params: object, options?: FormatOptions): string => {
72
+ if (Array.isArray(value)) {
73
+ const plural = options?.plural ?? defaultPlural ?? (defaultPlural = new Plural());
74
+ value = plural.select(u27n.locale, (params as FormatPluralParams).count, value);
75
+ }
76
+ if (Object.keys(params).length > 0) {
77
+ return interpolate(value, params);
78
+ }
79
+ return value;
80
+ };
81
+ }
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from "./core.js";
2
+ export * from "./format.js";