Skip to content

Commit 32c7e2d

Browse files
Add localization support (GH-99)
2 parents 7ff6ec4 + fe0abb1 commit 32c7e2d

File tree

5 files changed

+132
-8
lines changed

5 files changed

+132
-8
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ export default Demo;
5757
5858
The `valid` function primarily checks if a phone number has a length appropriate for its specified country. In addition, a more comprehensive validation can be performed, including verifying the dial and area codes' accuracy for the selected country. To activate the strict validation, pass `true` as the first argument to the `valid` function.
5959
60+
## Localization
61+
62+
The package provides a built-in localization feature that allows you to change the language of the component. The `locale` function returns the language object that can be passed to the `ConfigProvider` component of Ant Design.
63+
64+
```javascript
65+
import PhoneInput, {locale} from "antd-phone-input";
66+
67+
<ConfigProvider locale={locale("frFR")}>
68+
<PhoneInput/>
69+
</ConfigProvider>
70+
```
71+
72+
NOTE: If you use localization in the [documented](https://ant.design/docs/react/i18n) way, you should replace the object passed to the `locale` property with the `locale` function, specifying the desired language code.
73+
6074
## Props
6175
6276
Apart from the phone-specific properties described below, all [Input](https://ant.design/components/input#input) properties supported by the used Ant Design version can be applied to the phone input component.

package.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.3.8",
2+
"version": "0.3.9",
33
"name": "antd-phone-input",
44
"description": "Advanced, highly customizable phone input component for Ant Design.",
55
"keywords": [
@@ -46,20 +46,28 @@
4646
"default": "./styles.d.ts"
4747
}
4848
},
49+
"./locale": {
50+
"import": "./locale.js",
51+
"require": "./locale.cjs.js",
52+
"types": {
53+
"default": "./locale.d.ts"
54+
}
55+
},
4956
"./package.json": "./package.json"
5057
},
5158
"files": [
5259
"index*",
5360
"types*",
5461
"styles*",
62+
"locale*",
5563
"LICENSE",
5664
"resources",
5765
"README.md"
5866
],
5967
"scripts": {
6068
"rename": "bash -c 'for file in *.js; do mv $file \"${file%.js}.$0.js\"; done'",
6169
"build": "tsc --module commonjs && npm run rename -- cjs && tsc --declaration",
62-
"prebuild": "rm -r resources index* types* styles* || true",
70+
"prebuild": "rm -r resources index* locale* types* styles* || true",
6371
"postpack": "tsx scripts/prepare-package.ts",
6472
"test": "jest --config jestconfig.json",
6573
"postbuild": "cp -r src/resources ."
@@ -70,7 +78,7 @@
7078
"react": ">=16"
7179
},
7280
"dependencies": {
73-
"react-phone-hooks": "^0.1.5"
81+
"react-phone-hooks": "^0.1.6"
7482
},
7583
"devDependencies": {
7684
"@testing-library/react": "^14.0.0",

src/index.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
usePhone,
3333
} from "react-phone-hooks";
3434

35+
import locale from "./locale";
3536
import {injectMergedStyles} from "./styles";
3637
import {PhoneInputProps, PhoneNumber} from "./types";
3738

@@ -45,8 +46,8 @@ const PhoneInput = forwardRef(({
4546
onlyCountries = [],
4647
excludeCountries = [],
4748
preferredCountries = [],
48-
searchNotFound = "No country found",
49-
searchPlaceholder = "Search country",
49+
searchNotFound: defaultSearchNotFound = "No country found",
50+
searchPlaceholder: defaultSearchPlaceholder = "Search country",
5051
dropdownRender = (node) => node,
5152
onMount: handleMount = () => null,
5253
onInput: handleInput = () => null,
@@ -55,6 +56,7 @@ const PhoneInput = forwardRef(({
5556
...antInputProps
5657
}: PhoneInputProps, forwardedRef: any) => {
5758
const formInstance = useFormInstance();
59+
const {locale = {}} = useContext(ConfigContext);
5860
const formContext = useContext(FormContext);
5961
const {getPrefixCls} = useContext(ConfigContext);
6062
const inputRef = useRef<any>(null);
@@ -65,6 +67,12 @@ const PhoneInput = forwardRef(({
6567
const [minWidth, setMinWidth] = useState<number>(0);
6668
const [countryCode, setCountryCode] = useState<string>(country);
6769

70+
const {
71+
searchNotFound = defaultSearchNotFound,
72+
searchPlaceholder = defaultSearchPlaceholder,
73+
countries = new Proxy({}, ({get: (_: any, prop: any) => prop})),
74+
} = (locale as any).PhoneInput || {};
75+
6876
const prefixCls = getPrefixCls();
6977
injectMergedStyles(prefixCls);
7078

@@ -222,13 +230,13 @@ const PhoneInput = forwardRef(({
222230
label={<div className={`flag ${iso}`}/>}
223231
children={<div className={`${prefixCls}-phone-input-select-item`}>
224232
<div className={`flag ${iso}`}/>
225-
{name}&nbsp;{displayFormat(mask)}
233+
{countries[name]}&nbsp;{displayFormat(mask)}
226234
</div>}
227235
/>
228236
)
229237
})}
230238
</Select>
231-
), [selectValue, query, disabled, disableParentheses, disableDropdown, onDropdownVisibleChange, minWidth, searchNotFound, countriesList, setFieldValue, setValue, prefixCls, enableSearch, searchPlaceholder])
239+
), [selectValue, query, disabled, disableParentheses, disableDropdown, onDropdownVisibleChange, minWidth, searchNotFound, countries, countriesList, setFieldValue, setValue, prefixCls, enableSearch, searchPlaceholder])
232240

233241
return (
234242
<div className={`${prefixCls}-phone-input-wrapper`}
@@ -249,3 +257,4 @@ const PhoneInput = forwardRef(({
249257
})
250258

251259
export default PhoneInput;
260+
export {PhoneInputProps, PhoneNumber, locale};

src/locale.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import arEG from "antd/es/locale/ar_EG";
2+
import bnBD from "antd/es/locale/bn_BD";
3+
import csCZ from "antd/es/locale/cs_CZ";
4+
import elGR from "antd/es/locale/el_GR";
5+
import esES from "antd/es/locale/es_ES";
6+
import faIR from "antd/es/locale/fa_IR";
7+
import frCA from "antd/es/locale/fr_CA";
8+
import glES from "antd/es/locale/gl_ES";
9+
import hrHR from "antd/es/locale/hr_HR";
10+
import idID from "antd/es/locale/id_ID";
11+
import jaJP from "antd/es/locale/ja_JP";
12+
import kmKH from "antd/es/locale/km_KH";
13+
import koKR from "antd/es/locale/ko_KR";
14+
import lvLV from "antd/es/locale/lv_LV";
15+
import mnMN from "antd/es/locale/mn_MN";
16+
import nbNO from "antd/es/locale/nb_NO";
17+
import nlNL from "antd/es/locale/nl_NL";
18+
import ptPT from "antd/es/locale/pt_PT";
19+
import siLK from "antd/es/locale/si_LK";
20+
import srRS from "antd/es/locale/sr_RS";
21+
import thTH from "antd/es/locale/th_TH";
22+
import ukUA from "antd/es/locale/uk_UA";
23+
import viVN from "antd/es/locale/vi_VN";
24+
import zhTW from "antd/es/locale/zh_TW";
25+
import azAZ from "antd/es/locale/az_AZ";
26+
import byBY from "antd/es/locale/by_BY";
27+
import daDK from "antd/es/locale/da_DK";
28+
import enGB from "antd/es/locale/en_GB";
29+
import etEE from "antd/es/locale/et_EE";
30+
import fiFI from "antd/es/locale/fi_FI";
31+
import frFR from "antd/es/locale/fr_FR";
32+
import heIL from "antd/es/locale/he_IL";
33+
import huHU from "antd/es/locale/hu_HU";
34+
import isIS from "antd/es/locale/is_IS";
35+
import kaGE from "antd/es/locale/ka_GE";
36+
import kmrIQ from "antd/es/locale/kmr_IQ";
37+
import kuIQ from "antd/es/locale/ku_IQ";
38+
import mkMK from "antd/es/locale/mk_MK";
39+
import msMY from "antd/es/locale/ms_MY";
40+
import neNP from "antd/es/locale/ne_NP";
41+
import plPL from "antd/es/locale/pl_PL";
42+
import roRO from "antd/es/locale/ro_RO";
43+
import skSK from "antd/es/locale/sk_SK";
44+
import svSE from "antd/es/locale/sv_SE";
45+
import tkTK from "antd/es/locale/tk_TK";
46+
import urPK from "antd/es/locale/ur_PK";
47+
import zhCN from "antd/es/locale/zh_CN";
48+
import bgBG from "antd/es/locale/bg_BG";
49+
import caES from "antd/es/locale/ca_ES";
50+
import deDE from "antd/es/locale/de_DE";
51+
import enUS from "antd/es/locale/en_US";
52+
import frBE from "antd/es/locale/fr_BE";
53+
import gaIE from "antd/es/locale/ga_IE";
54+
import hiIN from "antd/es/locale/hi_IN";
55+
import hyAM from "antd/es/locale/hy_AM";
56+
import itIT from "antd/es/locale/it_IT";
57+
import kkKZ from "antd/es/locale/kk_KZ";
58+
import knIN from "antd/es/locale/kn_IN";
59+
import ltLT from "antd/es/locale/lt_LT";
60+
import mlIN from "antd/es/locale/ml_IN";
61+
import nlBE from "antd/es/locale/nl_BE";
62+
import ptBR from "antd/es/locale/pt_BR";
63+
import ruRU from "antd/es/locale/ru_RU";
64+
import slSI from "antd/es/locale/sl_SI";
65+
import taIN from "antd/es/locale/ta_IN";
66+
import trTR from "antd/es/locale/tr_TR";
67+
import zhHK from "antd/es/locale/zh_HK";
68+
import * as phoneLocale from "react-phone-hooks/locale";
69+
70+
const locale = {
71+
arEG, bnBD, csCZ, elGR, esES, faIR, frCA, glES, hrHR, idID, jaJP, kmKH, koKR, lvLV,
72+
mnMN, nbNO, nlNL, ptPT, siLK, srRS, thTH, ukUA, viVN, zhTW, azAZ, byBY, daDK, enGB,
73+
etEE, fiFI, frFR, heIL, huHU, isIS, kaGE, kmrIQ, kuIQ, mkMK, msMY, neNP, plPL, roRO,
74+
skSK, svSE, tkTK, urPK, zhCN, bgBG, caES, deDE, enUS, frBE, gaIE, hiIN, hyAM, itIT,
75+
kkKZ, knIN, ltLT, mlIN, nlBE, ptBR, ruRU, slSI, taIN, trTR, zhHK,
76+
}
77+
78+
type Locale = keyof typeof locale;
79+
80+
export default (lang: Locale) => ({
81+
...locale[lang],
82+
PhoneInput: (phoneLocale as any)[lang],
83+
})

tests/antd.test.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import ConfigProvider from "antd/lib/config-provider";
66
import userEvent from "@testing-library/user-event";
77
import {act, render, screen} from "@testing-library/react";
88

9-
import PhoneInput from "../src";
9+
import PhoneInput, {locale} from "../src";
1010

1111
Object.defineProperty(console, "warn", {
1212
value: jest.fn(),
@@ -34,6 +34,16 @@ describe("Checking the basic rendering and functionality", () => {
3434
assert(screen.getByDisplayValue("+1 (702) 123 4567"));
3535
})
3636

37+
it("Localization support check", async () => {
38+
const {container, getByText} = render(<ConfigProvider locale={locale("frFR")}>
39+
<PhoneInput onlyCountries={["am"]}/>
40+
</ConfigProvider>);
41+
await act(async () => {
42+
await userEvent.click(container.querySelector(".flag") as any);
43+
});
44+
assert(!!getByText(/Arménie[\S\s]+\+374/));
45+
})
46+
3747
it("Rendering with an initial value", () => {
3848
render(<PhoneInput
3949
onMount={(value: any) => {

0 commit comments

Comments
 (0)