Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/intl/.size-limit.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"gzip": true,
"path": "dist/index.production.js",
"import": "*",
"limit": "2 kB"
"limit": "2.05 kB"
},
{
"name": "All publics (Brotli)",
Expand All @@ -30,7 +30,7 @@
"gzip": true,
"path": "dist/index.production.js",
"import": "{ intl, text, number, datetime, params, plural, match, cases }",
"limit": "1 kB"
"limit": "1.05 kB"
},
{
"name": "Basic set (Brotli)",
Expand Down
29 changes: 29 additions & 0 deletions packages/intl/src/format/match.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,35 @@ describe('intl', () => {
count: 3
})).toBe('She has 3 tasks')
})

it('should use a string translation for every case', () => {
const format = match('gender')

expect(format(ctx, 'Invited {gender}.')({
gender: 'female'
})).toBe('Invited female.')

expect(format(ctx, 'Invited {gender}.')('male')).toBe('Invited male.')
})

it('should use a string translation for every case with cases resolver', () => {
const format = match('status', cases({
active: text('Active {status}'),
disabled: text('Disabled {status}')
}))

expect(format(ctx, 'Status {status}')({
status: 'active'
})).toBe('Status active')
})

it('should use a string translation for every case with default key resolver', () => {
const format = match('role', other('user'))

expect(format(ctx, 'Area of {role}')({
role: 'guest'
})).toBe('Area of guest')
})
})
})
})
17 changes: 9 additions & 8 deletions packages/intl/src/format/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export function match<
param: K,
getKey?: GetKey
): Format<
FormatsInput<B>,
FormatsInput<B> | string,
MatchFn<K, B>
>

Expand All @@ -113,7 +113,7 @@ export function match<
cases?: CasesFn<K, B>,
getKey?: GetKey
): Format<
FormatsInput<B>,
FormatsInput<B> | string,
MatchFn<K, B>
>

Expand All @@ -135,7 +135,7 @@ export function match<
},
maybeGetKey?: GetKey
): Format<
FormatsInput<B>,
FormatsInput<B> | string,
MatchFn<K, B>
> {
const valuePattern = new RegExp(`{${param}}`, 'g')
Expand All @@ -149,11 +149,13 @@ export function match<
getKey = maybeGetKey ?? casesOrGetKey ?? identity
}

return (ctx, input: FormatsInput<B> | undefined) => {
return (ctx, input: FormatsInput<B> | string | undefined) => {
const locale = ctx.$locale()
let resolvedCases: Record<string, string | undefined | MatchFn<K, B>> = input ?? {}
const isString = typeof input === 'string'
// A string never reaches the lookups below, so it is stored as is.
let resolvedCases = (input ?? {}) as Record<string, string | undefined | MatchFn<K, B>>

if (cases) {
if (cases && !isString) {
resolvedCases = {
...resolvedCases
}
Expand All @@ -163,8 +165,7 @@ export function match<

return (params) => {
const value = $get(typeof params === 'object' ? params[param] : params)
const key = getKey(value, locale, resolvedCases)
const resolvedCase = resolvedCases[key]
const resolvedCase = isString ? input : resolvedCases[getKey(value, locale, resolvedCases)]
const message = isFunction(resolvedCase) ? resolvedCase(params) : resolvedCase

return message?.replace(valuePattern, value as string)
Expand Down
21 changes: 21 additions & 0 deletions packages/intl/src/format/plural.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,27 @@ describe('intl', () => {
count: 3
})).toBe('She has 3 tasks')
})

it('should use a string translation for every form', () => {
const format = plural('count')

expect(format(ctx, '{count} going')({
count: 1
})).toBe('1 going')

expect(format(ctx, '{count} going')(3)).toBe('3 going')
})

it('should use a string translation for every form with forms resolver', () => {
const format = plural('count', forms({
one: text(),
other: text()
}))

expect(format(ctx, '{count} going')({
count: 1
})).toBe('1 going')
})
})
})
})
6 changes: 3 additions & 3 deletions packages/intl/src/format/plural.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function plural<
param: K,
forms?: CasesFn<K, B>
): Format<
FormatsInput<B>,
FormatsInput<B> | string,
MatchFn<K, B>
>

Expand All @@ -50,7 +50,7 @@ export function plural<
options: Intl.PluralRulesOptions,
forms?: CasesFn<K, B>
): Format<
FormatsInput<B>,
FormatsInput<B> | string,
MatchFn<K, B>
>

Expand All @@ -63,7 +63,7 @@ export function plural<
optionsOrForms?: Intl.PluralRulesOptions | CasesFn<K, B>,
maybeForms?: CasesFn<K, B>
): Format<
FormatsInput<B>,
FormatsInput<B> | string,
MatchFn<K, B>
> {
let options: Intl.PluralRulesOptions | undefined
Expand Down
4 changes: 2 additions & 2 deletions website/src/content/docs/intl/api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ $t().formatAmount([1, 5])

### `plural(param, forms?)`

Matches an LDML plural form with `Intl.PluralRules`. If `forms(...)` is omitted, `plural` reads forms directly from the translation input.
Matches an LDML plural form with `Intl.PluralRules`. If `forms(...)` is omitted, `plural` reads forms directly from the translation input. A plain string translation serves every form, which suits locales without plural distinctions.

```ts
const [$t] = messages('home', {
Expand Down Expand Up @@ -306,7 +306,7 @@ $t().guests({

### `match(param, cases?)`

Matches a case by parameter value. If `cases(...)` is omitted, `match` reads cases directly from the translation input.
Matches a case by parameter value. If `cases(...)` is omitted, `match` reads cases directly from the translation input. A plain string translation serves every case.

```ts
const [$t] = messages('invite', {
Expand Down