Skip to content

Commit f50cc69

Browse files
authored
Merge pull request #96 from haensl/95
#95: Add useLang hook.
2 parents 24b63d5 + 9396262 commit f50cc69

File tree

9 files changed

+1252
-974
lines changed

9 files changed

+1252
-974
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.13.0
2+
* [#95: Add `useLang` hook.](https://github.com/haensl/hooks/issues/95)
3+
* Update dependencies.
4+
15
## 1.12.2
26
* [#93: Update dependencies.](https://github.com/haensl/hooks/issues/93)
37

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const DebouncedButton = () => {
5353
* [`useIsMounted`](#useIsMounted): keep track of whether or not a component is mounted.
5454
* [`useIsomorphicLayoutEffect`](#useIsomorphicLayoutEffect): use this instead of [`useLayoutEffect`](https://reactjs.org/docs/hooks-reference.html#uselayouteffect) if your app uses serverside rendering (SSR).
5555
* [`useIsScrolling`](#useIsScrolling): keep track of whether or not the user is scrolling.
56+
* [`useLang`](#useLang): use the browser's language setting.
5657
* [`useOnScroll`](#useOnScroll): subscribe to scroll events.
5758
* [`usePrevious`](#usePrevious): keep track of a variable's previous value.
5859
* [`useWindowScroll`](#useWindowScroll): keep track of the `window`'s scroll position.
@@ -293,7 +294,7 @@ const MyComponent = () => {
293294

294295
Returns a `boolean` indicating whether or not the user is scrolling. You can subscribe to a specific element via the first argument, `el` _(default: `window`)_. End of scrolling is determined by no incoming scroll events for `scrollEndMs` milliseconds _(default: `100`)_. Please check the [example blow](#useIsScrollingExample) as well as the [Codepen example](https://codepen.io/haensl/pen/qBbqeWz)
295296

296-
##### Example<a name=useIsScrollingExample></a>
297+
##### Example<a name="useIsScrollingExample"></a>
297298

298299
```javascript
299300
import React from 'react';
@@ -310,6 +311,25 @@ const UserScrollTracker = () => {
310311

311312
#### [→ Codepen example](https://codepen.io/haensl/pen/qBbqeWz)
312313

314+
### `useLang({ defaultLang = 'en' }) => string` <a name="useLang"></a>
315+
316+
Returns the user's language setting from [`navigator.language`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/language). Use the `defaultLang` of the options parameter to set a default language. _(default: `'en`)_.
317+
318+
##### Example <a name="useLangExample"></a>
319+
320+
```javascript
321+
import React from 'react';
322+
import { useLang } from '@haensl/react-hooks';
323+
324+
const MyComponent = () => {
325+
const lang = useLang();
326+
327+
return (
328+
<span>The user's preferred language is { lang }.</span>
329+
);
330+
};
331+
```
332+
313333
### `useOnScroll(fn, [el = window])` <a name="useOnScroll"></a>
314334
315335
Subscribes to [`scroll`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scroll_event) events on the given element `el` _(default: `window`)_. The callback function `fn` is passed the [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scroll_event). Please check the [example below](#useOnScrollExample) as well as the [Codepen example](https://codepen.io/haensl/pen/wvMoLJK).

package-lock.json

Lines changed: 1114 additions & 972 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@haensl/react-hooks",
3-
"version": "1.12.2",
3+
"version": "1.13.0",
44
"description": "Assorted React hooks.",
55
"main": "dist/hooks.cjs.js",
66
"module": "dist/hooks.esm.js",
@@ -130,6 +130,7 @@
130130
},
131131
"devDependencies": {
132132
"@babel/core": "^7.12.10",
133+
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
133134
"@babel/plugin-transform-runtime": "^7.12.10",
134135
"@babel/preset-env": "^7.12.11",
135136
"@babel/preset-react": "^7.14.5",

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import _useInterval from './useInterval';
66
import _useIsMounted from './useIsMounted';
77
import _useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect';
88
import _useIsScrolling from './useIsScrolling';
9+
import _useLang from './useLang';
910
import _useOnScroll from './useOnScroll';
1011
import _usePrevious from './usePrevious';
1112
import _useWindowScroll from './useWindowScroll';
@@ -19,6 +20,7 @@ export const useInterval = _useInterval;
1920
export const useIsMounted = _useIsMounted;
2021
export const useIsomorphicLayoutEffect = _useIsomorphicLayoutEffect;
2122
export const useIsScrolling = _useIsScrolling;
23+
export const useLang = _useLang;
2224
export const useOnScroll = _useOnScroll;
2325
export const usePrevious = _usePrevious;
2426
export const useWindowScroll = _useWindowScroll;
@@ -33,6 +35,7 @@ const exports = {
3335
useIsMounted,
3436
useIsomorphicLayoutEffect,
3537
useIsScrolling,
38+
useLang,
3639
useOnScroll,
3740
usePrevious,
3841
useWindowScroll,

src/package-tests/cjs/cjs.test.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
useIsMounted,
1212
useIsomorphicLayoutEffect,
1313
useIsScrolling,
14+
useLang,
1415
useOnScroll,
1516
usePrevious,
1617
useWindowScroll,
@@ -206,6 +207,28 @@ describe('cjs module test', () => {
206207
});
207208
});
208209

210+
describe('useLang', () => {
211+
let TestComponent;
212+
213+
beforeAll(() => {
214+
TestComponent = () => {
215+
const lang = useLang();
216+
217+
return (
218+
<span>useLang test. { lang }</span>
219+
);
220+
};
221+
});
222+
223+
it('renders without crashing', () => {
224+
ReactDOM.render(
225+
<TestComponent />,
226+
container
227+
);
228+
ReactDOM.unmountComponentAtNode(container);
229+
});
230+
});
231+
209232
describe('useWindowScroll', () => {
210233
let TestComponent;
211234

src/package-tests/esm/esm.test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
useIsMounted,
1212
useIsomorphicLayoutEffect,
1313
useIsScrolling,
14+
useLang,
1415
useOnScroll,
1516
usePrevious,
1617
useWindowScroll,
@@ -206,6 +207,26 @@ describe('esm module test', () => {
206207
});
207208
});
208209

210+
describe('useLang', () => {
211+
let TestComponent;
212+
213+
beforeAll(() => {
214+
TestComponent = () => {
215+
const lang = useLang();
216+
217+
return (
218+
<span>useIsLang test. { lang }</span>
219+
);
220+
};
221+
});
222+
223+
it('renders without crashing', () => {
224+
expect(render.bind(render, <TestComponent />))
225+
.not
226+
.toThrow();
227+
});
228+
});
229+
209230
describe('useWindowScroll', () => {
210231
let TestComponent;
211232

src/useLang/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const useLang = ({ defaultLang = 'en' } = {}) => {
2+
if (typeof navigator === 'object') {
3+
return (navigator.language || navigator.userLanguage || defaultLang).slice(0, 2);
4+
}
5+
6+
return defaultLang;
7+
};
8+
9+
export default useLang;

src/useLang/useLang.hook.test.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { renderHook } from '@testing-library/react';
2+
import '@testing-library/jest-dom';
3+
4+
import useLang from './';
5+
6+
describe('useLang', () => {
7+
test('renders without crashing', () => {
8+
const { result } = renderHook(() => useLang());
9+
expect(result.error)
10+
.not
11+
.toBeDefined();
12+
});
13+
14+
describe('defaultLang', () => {
15+
let spy;
16+
beforeEach(() => {
17+
spy = jest.spyOn(navigator, 'language', 'get')
18+
.mockReturnValue(null);
19+
});
20+
21+
afterEach(() => {
22+
spy.mockRestore();
23+
});
24+
25+
it('defaults to "en"', () => {
26+
const { result } = renderHook(() => useLang());
27+
expect(result.current)
28+
.toEqual('en');
29+
});
30+
31+
it('can be set', () => {
32+
const { result } = renderHook(() => useLang({ defaultLang: 'de' }));
33+
expect(result.current)
34+
.toEqual('de');
35+
});
36+
});
37+
38+
describe('if navigator is available', () => {
39+
let spy;
40+
beforeEach(() => {
41+
spy = jest.spyOn(navigator, 'language', 'get')
42+
.mockReturnValue('fr');
43+
});
44+
45+
afterEach(() => {
46+
spy.mockRestore();
47+
});
48+
49+
test('takes lang from the navigator', () => {
50+
const { result } = renderHook(() => useLang());
51+
expect(result.current)
52+
.toEqual('fr');
53+
});
54+
});
55+
});

0 commit comments

Comments
 (0)