diff --git a/package.json b/package.json index aeab90a..62f38b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mehrzahl", - "version": "0.0.1-alpha2", + "version": "0.0.1-alpha3", "description": "Tagged template literals for singular/plural formatting", "source": "src/index.ts", "main": "lib/index.js", diff --git a/src/__tests__/mehrzahl.spec.ts b/src/__tests__/mehrzahl.spec.ts index 94f58b7..dceb073 100644 --- a/src/__tests__/mehrzahl.spec.ts +++ b/src/__tests__/mehrzahl.spec.ts @@ -23,10 +23,12 @@ describe("Mehrzahl function", () => { const formatSingular = mz(1) const formatPlural = mz(5) - expect(formatSingular`number is ${[null, 'plural']}`).toEqual("number is ") - expect(formatSingular`number is ${['singular']}`).toEqual("number is singular") - expect(formatPlural`number is ${[, 'plural']}`).toEqual("number is plural") - expect(formatPlural`number is ${['singular']}`).toEqual("number is ") + expect(formatSingular`number is ${[null, "plural"]}`).toEqual("number is ") + expect(formatSingular`number is ${["singular"]}`).toEqual( + "number is singular" + ) + expect(formatPlural`number is ${[, "plural"]}`).toEqual("number is plural") + expect(formatPlural`number is ${["singular"]}`).toEqual("number is ") }) it("interpolates singular/plural tuples and function expressions", () => { @@ -39,4 +41,40 @@ describe("Mehrzahl function", () => { expect(resultSingular).toEqual("number is singular singularFunction") expect(resultPlural).toEqual("number is plural pluralFunction") }) + + it("transforms {|} syntax", () => { + const resultSingular = mz(1)`number is {singular|plural}` + + const resultPlural = mz(5)`number is {singular|plural}` + + expect(resultSingular).toEqual("number is singular") + expect(resultPlural).toEqual("number is plural") + }) + + it("transforms {|} syntax with empty strings", () => { + const resultSingular = mz(1)`number is {singular|}` + + const resultPlural = mz(5)`number is {|plural}` + + expect(resultSingular).toEqual("number is singular") + expect(resultPlural).toEqual("number is plural") + }) + + it("transforms nested groups", () => { + const resultSingular = mz(1)`number is {singular ($value)|}` + + const resultPlural = mz(5)`number is {|plural ($value)}` + + expect(resultSingular).toEqual("number is singular (1)") + expect(resultPlural).toEqual("number is plural (5)") + }) + + it("replaces $value", () => { + const resultSingular = mz(1)`number is {singular ($value)|}` + + const resultPlural = mz(5)`number is {|plural ($value)}` + + expect(resultSingular).toEqual("number is singular (1)") + expect(resultPlural).toEqual("number is plural (5)") + }) }) diff --git a/src/mehrzahl.ts b/src/mehrzahl.ts index d9acced..f93479e 100644 --- a/src/mehrzahl.ts +++ b/src/mehrzahl.ts @@ -4,7 +4,8 @@ export type MehrzahlTaggedFormatter = ( ) => string export type MehrzahlFormatterFactory = ( - amount: number + amount: number, + delimiter?: string ) => MehrzahlTaggedFormatter export type InterpolationFunction = (plural: boolean, amount: number) => string @@ -20,11 +21,28 @@ export type InterpolatableValue = | number | InterpolationFunction +const DEFAULT_DELIMITER = "|" +const GROUPING_REGEX = /\{(.*?)\}/g + export const mz: MehrzahlFormatterFactory = - (amount) => + (amount, delimiter = DEFAULT_DELIMITER) => (strings, ...valuesToInterpolate) => { const isPlural = amount > 1 + const formatGroupSyntax = (value: string) => + value.replace(GROUPING_REGEX, (_, firstSubmatch) => { + if (typeof firstSubmatch === "string") { + const [singular, plural] = firstSubmatch.split(delimiter) + return isPlural ? plural : singular + } + + return firstSubmatch + }) + + if (strings.length === 1) { + return formatGroupSyntax(strings[0]).replace("$value", amount.toString()) + } + const interpolatedValues = valuesToInterpolate.map((value) => { if (typeof value === "function") { return value(isPlural, amount) @@ -34,13 +52,14 @@ export const mz: MehrzahlFormatterFactory = return value[isPlural ? 1 : 0]?.toString() ?? "" } - // ToDo: Interpolate {|} syntax return value.toString() }) - return strings.reduce( - (result, part, index) => - result + part + (interpolatedValues[index] ?? ""), - "" - ) + return formatGroupSyntax( + strings.reduce( + (result, part, index) => + result + part + (interpolatedValues[index] ?? ""), + "" + ) + ).replace("$value", amount.toString()) }