Load SAS Emoji translations from @matrix-org/spec (#11429)

* Remove last instance of componentWillMount

* Load SAS Emoji translations from @matrix-org/spec

* Fix import

* Test normalisation on both sides

* update comment for @richvdh

* Delint
This commit is contained in:
Michael Telatynski 2023-08-21 09:15:22 +01:00 committed by GitHub
parent 3d2d08b132
commit d81f71f993
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 147 deletions

View file

@ -16,9 +16,10 @@ limitations under the License.
import React from "react";
import { Device } from "matrix-js-sdk/src/matrix";
import { GeneratedSas } from "matrix-js-sdk/src/crypto-api/verification";
import { GeneratedSas, EmojiMapping } from "matrix-js-sdk/src/crypto-api/verification";
import SasEmoji from "@matrix-org/spec/sas-emoji.json";
import { _t, _td } from "../../../languageHandler";
import { _t, getNormalizedLanguageKeys, getUserLanguage } from "../../../languageHandler";
import { PendingActionSpinner } from "../right_panel/EncryptionInfo";
import AccessibleButton from "../elements/AccessibleButton";
import { fixupColorFonts } from "../../../utils/FontManager";
@ -42,19 +43,50 @@ interface IState {
cancelling?: boolean;
}
/** Convert the names of emojis returned by the js-sdk into the display names, which we use as
* a base for our translations.
const SasEmojiMap = new Map<
string, // lowercase
{
description: string;
translations: {
[normalizedLanguageKey: string]: string;
};
}
>(
SasEmoji.map(({ description, translated_descriptions: translations }) => [
description.toLowerCase(),
{
description,
// Normalize the translation keys
translations: Object.keys(translations).reduce<Record<string, string>>((o, k) => {
for (const key of getNormalizedLanguageKeys(k)) {
o[key] = translations[k as keyof typeof translations]!;
}
return o;
}, {}),
},
]),
);
/**
* Translate given EmojiMapping into the target locale
* @param mapping - the given EmojiMapping to translate
* @param locale - the BCP 47 locale to translate to, will fall back to English as the base locale for Matrix SAS Emoji.
*/
function capFirst(s: string): string {
// Our translations (currently) have names like "Thumbs up".
//
// With legacy crypto, the js-sdk returns lower-case names ("thumbs up"). With Rust crypto, the js-sdk follows
// the spec and returns title-case names ("Thumbs Up"). So, to convert both into names that match our i18n data,
// we upcase the first character and downcase the rest.
//
// Once legacy crypto is dead, we could consider getting rid of this and just making the i18n data use the
// title-case names (which would also match the spec).
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
export function tEmoji(mapping: EmojiMapping, locale: string): string {
const name = mapping[1];
const emoji = SasEmojiMap.get(name.toLowerCase());
if (!emoji) {
console.warn("Emoji not found for translation", name);
return name;
}
for (const key of getNormalizedLanguageKeys(locale)) {
if (!!emoji.translations[key]) {
return emoji.translations[key];
}
}
return emoji.description;
}
export default class VerificationShowSas extends React.Component<IProps, IState> {
@ -64,9 +96,7 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
this.state = {
pending: false,
};
}
public componentWillMount(): void {
// As this component is also used before login (during complete security),
// also make sure we have a working emoji font to display the SAS emojis here.
// This is also done from LoggedInView.
@ -84,13 +114,15 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
};
public render(): React.ReactNode {
const locale = getUserLanguage();
let sasDisplay;
let sasCaption;
if (this.props.sas.emoji) {
const emojiBlocks = this.props.sas.emoji.map((emoji, i) => (
<div className="mx_VerificationShowSas_emojiSas_block" key={i}>
<div className="mx_VerificationShowSas_emojiSas_emoji">{emoji[0]}</div>
<div className="mx_VerificationShowSas_emojiSas_label">{_t(capFirst(emoji[1]))}</div>
<div className="mx_VerificationShowSas_emojiSas_label">{tEmoji(emoji, locale)}</div>
</div>
));
sasDisplay = (
@ -171,69 +203,3 @@ export default class VerificationShowSas extends React.Component<IProps, IState>
);
}
}
// List of Emoji strings from the js-sdk, for i18n
_td("Dog");
_td("Cat");
_td("Lion");
_td("Horse");
_td("Unicorn");
_td("Pig");
_td("Elephant");
_td("Rabbit");
_td("Panda");
_td("Rooster");
_td("Penguin");
_td("Turtle");
_td("Fish");
_td("Octopus");
_td("Butterfly");
_td("Flower");
_td("Tree");
_td("Cactus");
_td("Mushroom");
_td("Globe");
_td("Moon");
_td("Cloud");
_td("Fire");
_td("Banana");
_td("Apple");
_td("Strawberry");
_td("Corn");
_td("Pizza");
_td("Cake");
_td("Heart");
_td("Smiley");
_td("Robot");
_td("Hat");
_td("Glasses");
_td("Spanner");
_td("Santa");
_td("Thumbs up");
_td("Umbrella");
_td("Hourglass");
_td("Clock");
_td("Gift");
_td("Light bulb");
_td("Book");
_td("Pencil");
_td("Paperclip");
_td("Scissors");
_td("Lock");
_td("Key");
_td("Hammer");
_td("Telephone");
_td("Flag");
_td("Train");
_td("Bicycle");
_td("Aeroplane");
_td("Rocket");
_td("Trophy");
_td("Ball");
_td("Guitar");
_td("Trumpet");
_td("Bell");
_td("Anchor");
_td("Headphones");
_td("Folder");
_td("Pin");

View file

@ -1221,69 +1221,6 @@
"They don't match": "They don't match",
"They match": "They match",
"To be secure, do this in person or use a trusted way to communicate.": "To be secure, do this in person or use a trusted way to communicate.",
"Dog": "Dog",
"Cat": "Cat",
"Lion": "Lion",
"Horse": "Horse",
"Unicorn": "Unicorn",
"Pig": "Pig",
"Elephant": "Elephant",
"Rabbit": "Rabbit",
"Panda": "Panda",
"Rooster": "Rooster",
"Penguin": "Penguin",
"Turtle": "Turtle",
"Fish": "Fish",
"Octopus": "Octopus",
"Butterfly": "Butterfly",
"Flower": "Flower",
"Tree": "Tree",
"Cactus": "Cactus",
"Mushroom": "Mushroom",
"Globe": "Globe",
"Moon": "Moon",
"Cloud": "Cloud",
"Fire": "Fire",
"Banana": "Banana",
"Apple": "Apple",
"Strawberry": "Strawberry",
"Corn": "Corn",
"Pizza": "Pizza",
"Cake": "Cake",
"Heart": "Heart",
"Smiley": "Smiley",
"Robot": "Robot",
"Hat": "Hat",
"Glasses": "Glasses",
"Spanner": "Spanner",
"Santa": "Santa",
"Thumbs up": "Thumbs up",
"Umbrella": "Umbrella",
"Hourglass": "Hourglass",
"Clock": "Clock",
"Gift": "Gift",
"Light bulb": "Light bulb",
"Book": "Book",
"Pencil": "Pencil",
"Paperclip": "Paperclip",
"Scissors": "Scissors",
"Lock": "Lock",
"Key": "Key",
"Hammer": "Hammer",
"Telephone": "Telephone",
"Flag": "Flag",
"Train": "Train",
"Bicycle": "Bicycle",
"Aeroplane": "Aeroplane",
"Rocket": "Rocket",
"Trophy": "Trophy",
"Ball": "Ball",
"Guitar": "Guitar",
"Trumpet": "Trumpet",
"Bell": "Bell",
"Anchor": "Anchor",
"Headphones": "Headphones",
"Folder": "Folder",
"Welcome": "Welcome",
"Secure messaging for friends and family": "Secure messaging for friends and family",
"With free end-to-end encrypted messaging, and unlimited voice and video calls, %(brand)s is a great way to stay in touch.": "With free end-to-end encrypted messaging, and unlimited voice and video calls, %(brand)s is a great way to stay in touch.",