Skip to content

Commit 0a9779a

Browse files
authored
feat(input-number, input, input-text): add built-in translations (#5458)
* feat(input-number, input, input-text): add built-in translations * fix test errors * restore TEXT in resources * prettify * remove duplicate code * refactor
1 parent ad3558a commit 0a9779a

File tree

8 files changed

+190
-34
lines changed

8 files changed

+190
-34
lines changed

src/components/input-number/input-number.e2e.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
labelable,
88
reflects,
99
renders,
10-
hidden
10+
hidden,
11+
t9n
1112
} from "../../tests/commonTests";
1213
import { html } from "../../../support/formatting";
1314
import { letterKeys, numberKeys } from "../../utils/key";
@@ -1350,4 +1351,6 @@ describe("calcite-input-number", () => {
13501351
testValue: 5,
13511352
submitsOnEnter: true
13521353
}));
1354+
1355+
it("supports translation", () => t9n("calcite-input-number"));
13531356
});

src/components/input-number/input-number.tsx

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
} from "@stencil/core";
1515
import { getElementDir, getElementProp, getSlotted, setRequestedIcon } from "../../utils/dom";
1616

17-
import { CSS, SLOTS, TEXT } from "./resources";
17+
import { CSS, SLOTS } from "./resources";
1818
import { InputPlacement } from "./interfaces";
1919
import { connectLabel, disconnectLabel, getLabelText, LabelableComponent } from "../../utils/label";
2020
import {
@@ -35,10 +35,18 @@ import {
3535
} from "../../utils/locale";
3636
import { numberKeys } from "../../utils/key";
3737
import { isValidNumber, parseNumberString, sanitizeNumberString } from "../../utils/number";
38-
import { CSS_UTILITY, TEXT as COMMON_TEXT } from "../../utils/resources";
38+
import { CSS_UTILITY } from "../../utils/resources";
3939
import { decimalPlaces } from "../../utils/math";
4040
import { createObserver } from "../../utils/observers";
4141
import { InteractiveComponent, updateHostInteraction } from "../../utils/interactive";
42+
import {
43+
connectMessages,
44+
disconnectMessages,
45+
setUpMessages,
46+
T9nComponent,
47+
updateMessages
48+
} from "../../utils/t9n";
49+
import { Messages } from "./assets/input-number/t9n";
4250

4351
type NumberNudgeDirection = "up" | "down";
4452
type setNumberValueOrigin = "initial" | "connected" | "user" | "reset" | "direct";
@@ -49,10 +57,16 @@ type setNumberValueOrigin = "initial" | "connected" | "user" | "reset" | "direct
4957
@Component({
5058
tag: "calcite-input-number",
5159
styleUrl: "input-number.scss",
52-
shadow: true
60+
shadow: true,
61+
assetsDirs: ["assets"]
5362
})
5463
export class InputNumber
55-
implements LabelableComponent, FormComponent, InteractiveComponent, LocalizedComponent
64+
implements
65+
LabelableComponent,
66+
FormComponent,
67+
InteractiveComponent,
68+
LocalizedComponent,
69+
T9nComponent
5670
{
5771
//--------------------------------------------------------------------------
5872
//
@@ -114,15 +128,18 @@ export class InputNumber
114128

115129
/**
116130
* A text label that will appear on the clear button for screen readers.
131+
*
132+
* @deprecated – translations are now built-in, if you need to override a string, please use `messageOverrides`.
117133
*/
118134
@Prop() intlClear?: string;
119135

120136
/**
121137
* Accessible name that will appear while loading.
122138
*
139+
* @deprecated – translations are now built-in, if you need to override a string, please use `messageOverrides`.
123140
* @default "Loading"
124141
*/
125-
@Prop() intlLoading?: string = COMMON_TEXT.loading;
142+
@Prop() intlLoading?: string;
126143

127144
/** When `true`, the icon will be flipped when the element direction is right-to-left (`"rtl"`). */
128145
@Prop({ reflect: true }) iconFlipRtl = false;
@@ -252,6 +269,26 @@ export class InputNumber
252269
/** The component's value. */
253270
@Prop({ mutable: true }) value = "";
254271

272+
/**
273+
* Made into a prop for testing purposes only
274+
*
275+
* @internal
276+
*/
277+
@Prop({ mutable: true }) messages: Messages;
278+
279+
/**
280+
* Use this property to override individual strings used by the component.
281+
*/
282+
@Prop({ mutable: true }) messageOverrides: Partial<Messages>;
283+
284+
@Watch("intlClear")
285+
@Watch("intlLoading")
286+
@Watch("defaultMessages")
287+
@Watch("messageOverrides")
288+
onMessagesChange(): void {
289+
/* wired up by t9n util */
290+
}
291+
255292
@Watch("value")
256293
valueWatcher(newValue: string, previousValue: string): void {
257294
if (!this.userChangedValue) {
@@ -323,6 +360,13 @@ export class InputNumber
323360

324361
@State() effectiveLocale = "";
325362

363+
@Watch("effectiveLocale")
364+
effectiveLocaleChange(): void {
365+
updateMessages(this, this.effectiveLocale);
366+
}
367+
368+
@State() defaultMessages: Messages;
369+
326370
@State() localizedValue: string;
327371

328372
//--------------------------------------------------------------------------
@@ -333,7 +377,7 @@ export class InputNumber
333377

334378
connectedCallback(): void {
335379
connectLocalized(this);
336-
380+
connectMessages(this);
337381
this.scale = getElementProp(this.el, "scale", this.scale);
338382
this.status = getElementProp(this.el, "status", this.status);
339383
this.inlineEditableEl = this.el.closest("calcite-inline-editable");
@@ -360,15 +404,17 @@ export class InputNumber
360404
disconnectLabel(this);
361405
disconnectForm(this);
362406
disconnectLocalized(this);
407+
disconnectMessages(this);
363408

364409
this.mutationObserver?.disconnect();
365410
this.el.removeEventListener("calciteInternalHiddenInputChange", this.hiddenInputChangeHandler);
366411
}
367412

368-
componentWillLoad(): void {
413+
async componentWillLoad(): Promise<void> {
369414
this.maxString = this.max?.toString();
370415
this.minString = this.min?.toString();
371416
this.requestedIcon = setRequestedIcon({}, this.icon, "number");
417+
await setUpMessages(this);
372418
}
373419

374420
componentShouldUpdate(newValue: string, oldValue: string, property: string): boolean {
@@ -791,13 +837,13 @@ export class InputNumber
791837
const dir = getElementDir(this.el);
792838
const loader = (
793839
<div class={CSS.loader}>
794-
<calcite-progress label={this.intlLoading} type="indeterminate" />
840+
<calcite-progress label={this.messages.loading} type="indeterminate" />
795841
</div>
796842
);
797843

798844
const inputClearButton = (
799845
<button
800-
aria-label={this.intlClear || TEXT.clear}
846+
aria-label={this.messages.clear}
801847
class={CSS.clearButton}
802848
disabled={this.disabled || this.readOnly}
803849
onClick={this.clearInputValue}

src/components/input-number/resources.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,3 @@ export const CSS = {
1818
export const SLOTS = {
1919
action: "action"
2020
};
21-
22-
export const TEXT = {
23-
clear: "Clear value"
24-
};

src/components/input-text/input-text.e2e.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
labelable,
88
reflects,
99
renders,
10-
hidden
10+
hidden,
11+
t9n
1112
} from "../../tests/commonTests";
1213
import { html } from "../../../support/formatting";
1314
import { TEXT } from "./resources";
@@ -364,4 +365,6 @@ describe("calcite-input-text", () => {
364365
});
365366

366367
it("is form-associated", () => formAssociated("calcite-input-text", { testValue: "test", submitsOnEnter: true }));
368+
369+
it("supports translation", () => t9n("calcite-input-text"));
367370
});

src/components/input-text/input-text.tsx

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import {
88
Host,
99
Method,
1010
Prop,
11+
State,
1112
VNode,
1213
Watch
1314
} from "@stencil/core";
1415
import { getElementDir, getElementProp, getSlotted, setRequestedIcon } from "../../utils/dom";
1516

16-
import { CSS, SLOTS, TEXT } from "./resources";
17+
import { CSS, SLOTS } from "./resources";
1718
import { Position } from "../interfaces";
1819
import { LabelableComponent, connectLabel, disconnectLabel, getLabelText } from "../../utils/label";
1920
import {
@@ -23,10 +24,18 @@ import {
2324
HiddenFormInputSlot,
2425
submitForm
2526
} from "../../utils/form";
26-
import { CSS_UTILITY, TEXT as COMMON_TEXT } from "../../utils/resources";
27-
27+
import { CSS_UTILITY } from "../../utils/resources";
2828
import { createObserver } from "../../utils/observers";
2929
import { InteractiveComponent, updateHostInteraction } from "../../utils/interactive";
30+
import { connectLocalized, disconnectLocalized, LocalizedComponent } from "../../utils/locale";
31+
import {
32+
connectMessages,
33+
disconnectMessages,
34+
setUpMessages,
35+
T9nComponent,
36+
updateMessages
37+
} from "../../utils/t9n";
38+
import { Messages } from "./assets/input-text/t9n";
3039

3140
type SetValueOrigin = "initial" | "connected" | "user" | "reset" | "direct";
3241

@@ -36,9 +45,17 @@ type SetValueOrigin = "initial" | "connected" | "user" | "reset" | "direct";
3645
@Component({
3746
tag: "calcite-input-text",
3847
styleUrl: "input-text.scss",
39-
shadow: true
48+
shadow: true,
49+
assetsDirs: ["assets"]
4050
})
41-
export class InputText implements LabelableComponent, FormComponent, InteractiveComponent {
51+
export class InputText
52+
implements
53+
LabelableComponent,
54+
FormComponent,
55+
InteractiveComponent,
56+
LocalizedComponent,
57+
T9nComponent
58+
{
4259
//--------------------------------------------------------------------------
4360
//
4461
// Element
@@ -94,15 +111,18 @@ export class InputText implements LabelableComponent, FormComponent, Interactive
94111

95112
/**
96113
* A text label that will appear on the clear button for screen readers.
114+
*
115+
* @deprecated – translations are now built-in, if you need to override a string, please use `messageOverrides`.
97116
*/
98117
@Prop() intlClear?: string;
99118

100119
/**
101120
* Accessible name that will appear while loading.
102121
*
103122
* @default "Loading"
123+
* @deprecated – translations are now built-in, if you need to override a string, please use `messageOverrides`.
104124
*/
105-
@Prop() intlLoading?: string = COMMON_TEXT.loading;
125+
@Prop() intlLoading?: string;
106126

107127
/** When `true`, the icon will be flipped when the element direction is right-to-left (`"rtl"`). */
108128
@Prop({ reflect: true }) iconFlipRtl = false;
@@ -171,6 +191,26 @@ export class InputText implements LabelableComponent, FormComponent, Interactive
171191
/** The component's value. */
172192
@Prop({ mutable: true }) value = "";
173193

194+
/**
195+
* Made into a prop for testing purposes only
196+
*
197+
* @internal
198+
*/
199+
@Prop({ mutable: true }) messages: Messages;
200+
201+
/**
202+
* Use this property to override individual strings used by the component.
203+
*/
204+
@Prop({ mutable: true }) messageOverrides: Partial<Messages>;
205+
206+
@Watch("intlClear")
207+
@Watch("intlLoading")
208+
@Watch("defaultMessages")
209+
@Watch("messageOverrides")
210+
onMessagesChange(): void {
211+
/* wired up by t9n util */
212+
}
213+
174214
@Watch("value")
175215
valueWatcher(newValue: string, previousValue: string): void {
176216
if (!this.userChangedValue) {
@@ -190,7 +230,7 @@ export class InputText implements LabelableComponent, FormComponent, Interactive
190230

191231
//--------------------------------------------------------------------------
192232
//
193-
// Private Properties
233+
// Private State/Properties
194234
//
195235
//--------------------------------------------------------------------------
196236

@@ -222,13 +262,25 @@ export class InputText implements LabelableComponent, FormComponent, Interactive
222262

223263
private userChangedValue = false;
224264

265+
@State() effectiveLocale: string;
266+
267+
@Watch("effectiveLocale")
268+
effectiveLocaleChange(): void {
269+
updateMessages(this, this.effectiveLocale);
270+
}
271+
272+
@State() defaultMessages: Messages;
273+
225274
//--------------------------------------------------------------------------
226275
//
227276
// Lifecycle
228277
//
229278
//--------------------------------------------------------------------------
230279

231280
connectedCallback(): void {
281+
connectLocalized(this);
282+
connectMessages(this);
283+
232284
this.scale = getElementProp(this.el, "scale", this.scale);
233285
this.status = getElementProp(this.el, "status", this.status);
234286
this.inlineEditableEl = this.el.closest("calcite-inline-editable");
@@ -248,12 +300,16 @@ export class InputText implements LabelableComponent, FormComponent, Interactive
248300
disconnectedCallback(): void {
249301
disconnectLabel(this);
250302
disconnectForm(this);
303+
disconnectLocalized(this);
304+
disconnectMessages(this);
305+
251306
this.mutationObserver?.disconnect();
252307
this.el.removeEventListener("calciteInternalHiddenInputChange", this.hiddenInputChangeHandler);
253308
}
254309

255-
componentWillLoad(): void {
310+
async componentWillLoad(): Promise<void> {
256311
this.requestedIcon = setRequestedIcon({}, this.icon, "text");
312+
await setUpMessages(this);
257313
}
258314

259315
componentDidRender(): void {
@@ -496,13 +552,13 @@ export class InputText implements LabelableComponent, FormComponent, Interactive
496552
const dir = getElementDir(this.el);
497553
const loader = (
498554
<div class={CSS.loader}>
499-
<calcite-progress label={this.intlLoading} type="indeterminate" />
555+
<calcite-progress label={this.messages.loading} type="indeterminate" />
500556
</div>
501557
);
502558

503559
const inputClearButton = (
504560
<button
505-
aria-label={this.intlClear || TEXT.clear}
561+
aria-label={this.messages.clear}
506562
class={CSS.clearButton}
507563
disabled={this.disabled || this.readOnly}
508564
onClick={this.clearInputTextValue}

src/components/input/input.e2e.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
labelable,
88
reflects,
99
renders,
10-
hidden
10+
hidden,
11+
t9n
1112
} from "../../tests/commonTests";
1213
import { html } from "../../../support/formatting";
1314
import { letterKeys, numberKeys } from "../../utils/key";
@@ -1602,4 +1603,6 @@ describe("calcite-input", () => {
16021603
it("supports type=number", () =>
16031604
formAssociated("<calcite-input type='number'></calcite-input>", { testValue: 5, submitsOnEnter: true }));
16041605
});
1606+
1607+
it("supports translation", () => t9n("calcite-input"));
16051608
});

0 commit comments

Comments
 (0)