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

feat(rating): add built-in translations #5437

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ce4e9d1
feat(rating): add built-in translations
jcfranco Oct 11, 2022
7d0c710
set asset dir
jcfranco Oct 11, 2022
86cb8b5
add initial message load
jcfranco Oct 11, 2022
e4a8b5b
add effectiveLocale watcher
jcfranco Oct 11, 2022
949d55e
fix outdated reference
jcfranco Oct 11, 2022
28d564c
update lang switch helper to account for strings used in rendering
jcfranco Oct 12, 2022
7eaf051
feat(time-picker, input-time-picker): add numberingSystem property (#…
benelan Oct 13, 2022
d81065d
refactor(block): move hardcoded classes to CSS object (#5474)
jcfranco Oct 13, 2022
3d6ba64
fix(input, input-number, input-text): fix input icons not displaying …
jcfranco Oct 14, 2022
a647345
ci(next): clean docs build before deployment (#5476)
benelan Oct 14, 2022
3898927
refactor(input-number, input-text): drop resize-icon selectors (#5477)
jcfranco Oct 14, 2022
2cc0a5f
fix(block): improve content layout (#5473)
jcfranco Oct 14, 2022
66bf66e
docs: update component READMEs (#5479)
calcite-admin Oct 14, 2022
048527b
docs: add backticks to props and values for consistency (#5485)
geospatialem Oct 17, 2022
d10593e
fix(date-picker): no longer hides year for zh-CN locale (#5344)
anveshmekala Oct 17, 2022
5e3d7ab
docs(changelog): add missing breaking changes (#5469)
jcfranco Oct 17, 2022
9ca3117
feat(stepper, stepper-item): add numberingSystem property (#5467)
benelan Oct 17, 2022
246e470
fix(flow-item): fix scrollContentTo (#5487)
jcfranco Oct 17, 2022
f579f06
ci(next): fix next releases take 3 (#5497)
benelan Oct 17, 2022
96dcb78
fix(flow-item, panel): fix layout issue that would cause double scrol…
jcfranco Oct 17, 2022
5419b52
1.0.0-next.598
benelan Oct 18, 2022
072a09e
docs: update component READMEs (#5501)
calcite-admin Oct 18, 2022
826ab24
build(deps): bump eslint-plugin-jest from 27.1.1 to 27.1.2 (#5507)
dependabot[bot] Oct 18, 2022
0a44d80
build(deps): bump shell-quote from 1.7.3 to 1.7.4 (#5503)
dependabot[bot] Oct 18, 2022
f521c1a
build(deps): bump @typescript-eslint/eslint-plugin from 5.38.1 to 5.4…
dependabot[bot] Oct 18, 2022
e1d06f9
build(deps): bump @typescript-eslint/parser from 5.38.1 to 5.40.1 (#5…
dependabot[bot] Oct 18, 2022
06ab974
build(deps): bump eslint-plugin-jsdoc from 39.3.6 to 39.3.13 (#5505)
dependabot[bot] Oct 18, 2022
8ac3785
fix(tree, tree-item): works when tree is the topmost element in a sha…
Elijbet Oct 18, 2022
553e419
ci: fix next releases take 4 (#5500)
benelan Oct 18, 2022
cb4835b
1.0.0-next.599
github-actions[bot] Oct 18, 2022
35b10e7
fix(flow-item): Render back button first. (#5511)
driskull Oct 18, 2022
c63b8d8
1.0.0-next.600
github-actions[bot] Oct 18, 2022
f3e06a4
fix(tab): applies section styles onto the enclosing parent (#5516)
Elijbet Oct 18, 2022
b12b123
1.0.0-next.601
github-actions[bot] Oct 18, 2022
a6f76c0
merge master
jcfranco Oct 19, 2022
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
13 changes: 12 additions & 1 deletion src/components/rating/rating.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { newE2EPage } from "@stencil/core/testing";
import { renders, accessible, focusable, labelable, formAssociated, disabled, hidden } from "../../tests/commonTests";
import {
renders,
accessible,
focusable,
labelable,
formAssociated,
disabled,
hidden,
t9n
} from "../../tests/commonTests";

describe("calcite-rating", () => {
it("renders", async () => renders("<calcite-rating></calcite-rating>", { display: "flex" }));
Expand All @@ -12,6 +21,8 @@ describe("calcite-rating", () => {

it("can be disabled", () => disabled("<calcite-rating value='3'></calcite-rating>"));

it("supports translations", () => t9n("calcite-rating"));

it("renders outlined star when no value or average is set", async () => {
const page = await newE2EPage();
await page.setContent("<calcite-rating></calcite-rating>");
Expand Down
114 changes: 84 additions & 30 deletions src/components/rating/rating.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,39 @@ import {
Method,
Prop,
State,
VNode
VNode,
Watch
} from "@stencil/core";
import { guid } from "../../utils/guid";
import { Scale } from "../interfaces";
import { LabelableComponent, connectLabel, disconnectLabel } from "../../utils/label";
import { connectForm, disconnectForm, FormComponent, HiddenFormInputSlot } from "../../utils/form";
import { TEXT } from "./resources";
import { InteractiveComponent, updateHostInteraction } from "../../utils/interactive";
import { isActivationKey } from "../../utils/key";
import { connectLocalized, disconnectLocalized, LocalizedComponent } from "../../utils/locale";
import {
connectMessages,
disconnectMessages,
setUpMessages,
T9nComponent,
updateMessages
} from "../../utils/t9n";
import { Messages } from "./assets/rating/t9n";

@Component({
tag: "calcite-rating",
styleUrl: "rating.scss",
shadow: true
shadow: true,
assetsDirs: ["assets"]
})
export class Rating implements LabelableComponent, FormComponent, InteractiveComponent {
export class Rating
implements
LabelableComponent,
FormComponent,
InteractiveComponent,
LocalizedComponent,
T9nComponent
{
//--------------------------------------------------------------------------
//
// Element
Expand All @@ -39,43 +56,54 @@ export class Rating implements LabelableComponent, FormComponent, InteractiveCom
//
// --------------------------------------------------------------------------

/** Specifies the size of the component. */
@Prop({ reflect: true }) scale: Scale = "m";

/** The component's value. */
@Prop({ reflect: true, mutable: true }) value = 0;

/** When true, the component's value can be read, but cannot be modified. */
@Prop({ reflect: true }) readOnly = false;

/** When true, interaction is prevented and the component is displayed with lower opacity. */
@Prop({ reflect: true }) disabled = false;

/** When true, and if available, displays the "average" and/or "count" data summary in a `calcite-chip`. */
@Prop({ reflect: true }) showChip = false;
/** Specifies a cumulative average from previous ratings to display. */
@Prop({ reflect: true }) average?: number;

/** Specifies the number of previous ratings to display. */
@Prop({ reflect: true }) count?: number;

/** Specifies a cumulative average from previous ratings to display. */
@Prop({ reflect: true }) average?: number;

/** Specifies the name of the component on form submission. */
@Prop({ reflect: true }) name: string;
/** When true, interaction is prevented and the component is displayed with lower opacity. */
@Prop({ reflect: true }) disabled = false;

/**
* Accessible name for the component.
*
* @default "Rating"
* @deprecated – translations are now built-in, if you need to override a string, please use `messageOverrides`
*/
@Prop() intlRating?: string = TEXT.rating;
@Prop() intlRating: string;

/**
* Accessible name for each star. The `${num}` in the string will be replaced by the number.
*
* @default "Stars: ${num}"
* @deprecated – translations are now built-in, if you need to override a string, please use `messageOverrides`
*/
@Prop() intlStars: string;

/**
* Made into a prop for testing purposes only
*
* @internal
*/
@Prop() intlStars?: string = TEXT.stars;
@Prop({ mutable: true }) messages: Messages;

/**
* Use this property to override individual strings used by the component.
*/
@Prop({ mutable: true }) messageOverrides: Partial<Messages>;

@Watch("intlRating")
@Watch("intlStars")
@Watch("defaultMessages")
@Watch("messageOverrides")
onMessagesChange(): void {
/* wired up by t9n util */
}

/** Specifies the name of the component on form submission. */
@Prop({ reflect: true }) name: string;

/** When true, the component's value can be read, but cannot be modified. */
@Prop({ reflect: true }) readOnly = false;

/**
* When true, the component must have a value in order for the form to submit.
Expand All @@ -84,18 +112,35 @@ export class Rating implements LabelableComponent, FormComponent, InteractiveCom
*/
@Prop({ reflect: true }) required = false;

/** Specifies the size of the component. */
@Prop({ reflect: true }) scale: Scale = "m";

/** When true, and if available, displays the "average" and/or "count" data summary in a `calcite-chip`. */
@Prop({ reflect: true }) showChip = false;

/** The component's value. */
@Prop({ reflect: true, mutable: true }) value = 0;

//--------------------------------------------------------------------------
//
// Lifecycle
//
//--------------------------------------------------------------------------

connectedCallback(): void {
connectLocalized(this);
connectMessages(this);
connectLabel(this);
connectForm(this);
}

async componentWillLoad(): Promise<void> {
await setUpMessages(this);
}

disconnectedCallback(): void {
disconnectLocalized(this);
disconnectMessages(this);
disconnectLabel(this);
disconnectForm(this);
}
Expand Down Expand Up @@ -160,7 +205,7 @@ export class Rating implements LabelableComponent, FormComponent, InteractiveCom
<calcite-icon icon="star-f" scale={this.scale} />
</div>
)}
<span class="visually-hidden">{this.intlStars.replace("${num}", `${i}`)}</span>
<span class="visually-hidden">{this.messages.stars.replace("${num}", `${i}`)}</span>
</label>
<input
checked={i === this.value}
Expand All @@ -187,7 +232,7 @@ export class Rating implements LabelableComponent, FormComponent, InteractiveCom
}

render() {
const { disabled, intlRating, showChip, scale, count, average } = this;
const { disabled, messages, showChip, scale, count, average } = this;

return (
<Fragment>
Expand All @@ -198,7 +243,7 @@ export class Rating implements LabelableComponent, FormComponent, InteractiveCom
onPointerLeave={() => (this.hoverValue = null)}
onTouchEnd={() => (this.hoverValue = null)}
>
<legend class="visually-hidden">{intlRating}</legend>
<legend class="visually-hidden">{messages.rating}</legend>
{this.renderStars()}
</fieldset>
{(count || average) && showChip ? (
Expand Down Expand Up @@ -267,6 +312,15 @@ export class Rating implements LabelableComponent, FormComponent, InteractiveCom

defaultValue: Rating["value"];

@State() effectiveLocale = "";

@Watch("effectiveLocale")
effectiveLocaleChange(): void {
updateMessages(this, this.effectiveLocale);
}

@State() defaultMessages: Messages;

@State() hoverValue: number;

@State() focusValue: number;
Expand Down
4 changes: 0 additions & 4 deletions src/components/rating/resources.ts

This file was deleted.

34 changes: 22 additions & 12 deletions src/tests/commonTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -974,25 +974,35 @@ export async function t9n(componentSetup: TagOrHTML | TagAndPage): Promise<void>
}

async function assertLangSwitch(): Promise<void> {
await page.evaluate(() => {
const orig = window.fetch;
window.fetch = async function (input, init) {
if (typeof input === "string" && input.endsWith("messages_es.json")) {
const dummyMessages = {};
window.fetch = orig;
return new Response(new Blob([JSON.stringify(dummyMessages, null, 2)], { type: "application/json" }));
}
const enMessages = await getCurrentMessages();
const fakeBundleIdentifier = "__fake__";
await page.evaluate(
(enMessages, fakeBundleIdentifier) => {
const orig = window.fetch;
window.fetch = async function (input, init) {
if (typeof input === "string" && input.endsWith("messages_es.json")) {
const fakeEsMessages = {
...enMessages, // reuse real message bundle in case component rendering depends on strings

[fakeBundleIdentifier]: true // we inject a fake identifier for assertion-purposes
};
window.fetch = orig;
return new Response(new Blob([JSON.stringify(fakeEsMessages, null, 2)], { type: "application/json" }));
}

return orig.call(input, init);
};
});
return orig.call(input, init);
};
},
enMessages,
fakeBundleIdentifier
);

component.setAttribute("lang", "es");
await page.waitForChanges();
await page.waitForTimeout(3000);
const esMessages = await getCurrentMessages();

expect(esMessages).toEqual({});
expect(esMessages).toHaveProperty(fakeBundleIdentifier);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can assert esMessages toEqual enMessage without the need of adding fakeBundleIdentifier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we did so, this would no longer catch problems with locale bundle switching as the en one wouldn't change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense.


// reset test changes
component.removeAttribute("lang");
Expand Down