Skip to content
Open
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
19 changes: 15 additions & 4 deletions docs/defining-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ parameter = string
* each `field` is mapped to a field name on the block.
* the function parameters are mapped to the `$parameter` argument with an identical name. The loader automatically builds a mapping between the block field names and the function names.
* the block will automatically switch to external inputs (wrapping) when there are four or more parameters.
* the `|` indicates where to start a new line if the block is in external inputs mode.
* the `|` indicates where to start a new line if the block is in external inputs mode.

## Custom block localization

Expand All @@ -124,11 +124,12 @@ For example,
export function square(x: number): number {}
```

You can also override the ``jsdoc`` description and parameter info.
You can also override the ``jsdoc`` description, parameter info, and ariaLabel (for dropdown values).

```
jsdoc.loc.LOCALE = translated jsdoc
PARAM.loc.LOCALE = parameter jsdoc
ariaLabel.loc.LOCALE = translated aria label
```

```typescript-ignore
Expand All @@ -141,6 +142,14 @@ PARAM.loc.LOCALE = parameter jsdoc
//% jsdoc.loc.fr="Calcule le carré de x"
//% x.loc.fr="le nombre"
export function square(x: number): number {}


export enum MyEnum {
//% block="x"
//% ariaLabel="x axis"
//% ariaLabel.loc.fr="axe des x"
X
}
```


Expand Down Expand Up @@ -339,14 +348,16 @@ Enum is supported and will automatically be represented by a dropdown in blocks.
enum Button {
A = 1,
B = 2,
//% blockId="ApB" block="A+B"
//% block="A+B" ariaLabel="A and B"
AB = 3,
}
```

* the initializer can be used to map the value
* the `blockId` attribute can be used to override the block id
* the `block` attribute can be used to override the rendered string
* the `ariaLabel` attribute can be used to override the aria label on the dropdown value if the `block` value is not read correctly by screen readers

The `block` and `ariaLabel` values can both be localized, either by including a strings JSON file or locally in the comments (see custom block localization section above).

### Tip: dropdown for non-enum parameters

Expand Down
2 changes: 2 additions & 0 deletions localtypings/pxtarget.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,7 @@ declare namespace ts.pxtc {
enumIsHash?: boolean; // if true, the name of the enum is normalized, then hashed to generate the value
enumPromptHint?: string; // The hint that will be displayed in the member creation prompt
enumInitialMembers?: string[]; // The initial enum values which will be given the lowest values available
ariaLabel?: string; // The aria label for the enum value if the screen reader text should differ from the block value in dropdown items

/* end enum-only attributes */

Expand Down Expand Up @@ -1017,6 +1018,7 @@ declare namespace ts.pxtc {
_untranslatedBlock?: string; // The block definition before it was translated
_untranslatedJsDoc?: string // the jsDoc before it was translated
_untranslatedParamDefl?: pxt.Map<string>; // the parameter defaults before they were translated
_untranslatedAriaLabel?: string; // the aria label before it was translated
_translatedLanguageCode?: string // the language this block has been translated into
_shadowOverrides?: pxt.Map<string>;
jsDoc?: string;
Expand Down
3 changes: 2 additions & 1 deletion pxtblocks/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,8 @@ function initBlock(block: Blockly.Block, info: pxtc.BlocksInfo, fn: pxtc.SymbolI
height: 36,
value: v.name
} : k,
v.namespace + "." + v.name
v.namespace + "." + v.name,
v.attributes.ariaLabel
];
});
// if a value is provided, move it first
Expand Down
5 changes: 5 additions & 0 deletions pxtcompiler/emitter/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,10 @@ namespace ts.pxtc {
}
}
}

if (si.attributes.ariaLabel) {
locStrings[`${si.qName}|ariaLabel`] = si.attributes.ariaLabel;
}
}
const mapLocs = (m: pxt.Map<string>, name: string) => {
if (!options.locs) return;
Expand All @@ -385,6 +389,7 @@ namespace ts.pxtc {
if (options.locs)
enumMembers.forEach(em => {
if (em.attributes.block) locStrings[`${em.qName}|block`] = em.attributes.block;
if (em.attributes.ariaLabel) locStrings[`${em.qName}|ariaLabel`] = em.attributes.ariaLabel;
if (em.attributes.jsDoc) locStrings[em.qName] = em.attributes.jsDoc;
});
mapLocs(locStrings, "");
Expand Down
15 changes: 14 additions & 1 deletion pxtlib/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ namespace ts.pxtc {
const langLower = lang.toLowerCase();
const attrJsLocsKey = langLower + "|jsdoc";
const attrBlockLocsKey = langLower + "|block";
const attrAriaLabelLocsKey = langLower + "|ariaLabel";

const loc = await mainPkg.localizationStringsAsync(lang);
if (apiLocalizationStrings)
Expand All @@ -717,7 +718,8 @@ namespace ts.pxtc {
const altLocSrcFn = altLocSrc && apis.byQName[altLocSrc];

if (fn.attributes._untranslatedJsDoc) fn.attributes.jsDoc = fn.attributes._untranslatedJsDoc;
if (fn.attributes._untranslatedBlock) fn.attributes.jsDoc = fn.attributes._untranslatedBlock;
if (fn.attributes._untranslatedBlock) fn.attributes.block = fn.attributes._untranslatedBlock;
if (fn.attributes._untranslatedAriaLabel) fn.attributes.ariaLabel = fn.attributes._untranslatedAriaLabel;
if (fn.attributes._untranslatedParamDefl) {
fn.attributes.paramDefl = U.clone(fn.attributes._untranslatedParamDefl);
syncParameterDefaults(fn);
Expand Down Expand Up @@ -747,6 +749,7 @@ namespace ts.pxtc {

const nsDoc = loc['{id:category}' + Util.capitalize(fn.qName)];
let locBlock = loc[`${fn.qName}|block`] || fn.attributes.locs?.[attrBlockLocsKey];
const locAriaLabel = loc[`${fn.qName}|ariaLabel`] || fn.attributes.locs?.[attrAriaLabelLocsKey];

if (fn.attributes.block) {
const comp = pxt.blocks.compileInfo(fn);
Expand Down Expand Up @@ -848,6 +851,13 @@ namespace ts.pxtc {
} else {
updateBlockDef(fn.attributes);
}

if (locAriaLabel) {
if (!fn.attributes._untranslatedAriaLabel) {
fn.attributes._untranslatedAriaLabel = fn.attributes.ariaLabel;
}
fn.attributes.ariaLabel = locAriaLabel;
}
fn.attributes._translatedLanguageCode = lang;
});

Expand Down Expand Up @@ -990,6 +1000,9 @@ namespace ts.pxtc {
} else if (U.startsWith(n, "jsdoc.loc.")) {
if (!res.locs) res.locs = {};
res.locs[n.slice("jsdoc.loc.".length).toLowerCase() + "|jsdoc"] = v;
} else if (U.startsWith(n, "ariaLabel.loc.")) {
if (!res.locs) res.locs = {};
res.locs[n.slice("ariaLabel.loc.".length).toLowerCase() + "|ariaLabel"] = v;
} else if (U.contains(n, ".loc.")) {
if (!res.locs) res.locs = {};
const p = n.slice(0, n.indexOf('.loc.'));
Expand Down
5 changes: 5 additions & 0 deletions webapp/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,11 @@ function cleanApiForCache(apiInfo: pxtc.SymbolInfo) {
delete cachedAttrs._untranslatedJsDoc;
defChanged = true;
}
if (cachedAttrs._untranslatedAriaLabel) {
cachedAttrs.ariaLabel = cachedAttrs._untranslatedAriaLabel;
delete cachedAttrs._untranslatedAriaLabel;
defChanged = true;
}
if (defChanged) {
ts.pxtc.updateBlockDef(cachedAttrs);
}
Expand Down
Loading