Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for nesting translations #368

Merged
merged 3 commits into from
Dec 4, 2020
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
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ To work well, it is necessary that your `_app.js` will be wrapped with the [appW

## 5. Plurals

We support 6 plural forms (taken from [CLDR Plurals](http://cldr.unicode.org/index/cldr-spec/plural-rules) page) by adding to the key this suffix:
We support 6 plural forms (taken from [CLDR Plurals](http://cldr.unicode.org/index/cldr-spec/plural-rules) page) by adding to the key this suffix (or nesting it under the key with no `_` prefix):

- `_zero`
- `_one` (singular)
Expand Down Expand Up @@ -498,6 +498,19 @@ t('cart-message', { count })
}
```

or

```js
{
"cart-message": {
"0": "The cart is empty", // when count === 0
"one": "The cart has only {{count}} product", // singular
"other": "The cart has {{count}} products", // plural
"999": "The cart is full", // when count === 999
}
}
```


## 6. Use HTML inside the translation

Expand Down
118 changes: 118 additions & 0 deletions __tests__/useTranslation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,124 @@ describe('useTranslation', () => {
)
expect(container.textContent).toContain(expected)
})

describe('nested', () => {
test('should work with 0 | count=0', () => {
const i18nKey = 'ns:withzero'
const expected = 'The number is ZERO!'
const with_0 = {
withzero: {
one: 'The number is NOT ZERO',
other: 'The number is not ZERO!',
0: 'The number is ZERO!',
},
}
const { container } = render(
<TestEnglish
namespaces={{ ns: with_0 }}
i18nKey={i18nKey}
query={{ count: 0 }}
/>
)
expect(container.textContent).toContain(expected)
})

test('should work with zero | count=0', () => {
const i18nKey = 'ns:withzero'
const expected = 'The number is ZERO!'
const with_0 = {
withzero: {
one: 'The number is NOT ZERO',
other: 'The number is ZERO!',
},
}
const { container } = render(
<TestEnglish
namespaces={{ ns: with_0 }}
i18nKey={i18nKey}
query={{ count: 0 }}
/>
)
expect(container.textContent).toContain(expected)
})

test('should work with singular | count=1', () => {
const i18nKey = 'ns:withsingular'
const expected = 'The number is NOT ZERO'
const withSingular = {
withsingular: {
one: 'The number is NOT ZERO',
other: 'Oops!',
},
}
const { container } = render(
<TestEnglish
namespaces={{ ns: withSingular }}
i18nKey={i18nKey}
query={{ count: 1 }}
/>
)
expect(container.textContent).toContain(expected)
})

test('should work with 1 | count=1', () => {
const i18nKey = 'ns:withsingular'
const expected = 'The number is NOT ZERO'
const withSingular = {
withsingular: {
1: 'The number is NOT ZERO',
other: 'Oops!',
},
}
const { container } = render(
<TestEnglish
namespaces={{ ns: withSingular }}
i18nKey={i18nKey}
query={{ count: 1 }}
/>
)
expect(container.textContent).toContain(expected)
})

test('should work with plural | count=2', () => {
const i18nKey = 'ns:withplural'
const expected = 'Number is bigger than one!'
const withPlural = {
withplural: {
one: 'Singular',
other: 'Number is bigger than one!',
},
}
const { container } = render(
<TestEnglish
namespaces={{ ns: withPlural }}
i18nKey={i18nKey}
query={{ count: 2 }}
/>
)
expect(container.textContent).toContain(expected)
})

test('should work with 2 | count=2', () => {
const i18nKey = 'ns:withplural'
const expected = 'Number is 2!'
const withPlural = {
withplural: {
one: 'Singular',
2: 'Number is 2!',
other: 'Number is bigger than one!',
},
}
const { container } = render(
<TestEnglish
namespaces={{ ns: withPlural }}
i18nKey={i18nKey}
query={{ count: 2 }}
/>
)
expect(container.textContent).toContain(expected)
})
})
})

describe('options', () => {
Expand Down
17 changes: 13 additions & 4 deletions src/I18nProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ function getDicValue(
): string | undefined | unknown {
const value: string | unknown = key
.split('.')
.reduce(
(val: Object, key: string) => val[key as keyof typeof val] || {},
dic
)
.reduce((val: Object, key: string) => {
if (typeof val === 'string') {
return {}
}

return val[key as keyof typeof val] || {}
}, dic)

if (
typeof value === 'string' ||
Expand Down Expand Up @@ -50,6 +53,12 @@ function plural(
return pluralKey
}

const nestedNumKey = `${key}.${query.count}`
if (getDicValue(dic, nestedNumKey) !== undefined) return nestedNumKey

const nestedKey = `${key}.${pluralRules.select(query.count)}`
if (getDicValue(dic, nestedKey) !== undefined) return nestedKey

return key
}

Expand Down