l10n-pseudo.mjs (4281B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // Stolen from https://github.com/firefox-devtools/profiler/blob/52a7531662a08d96dc8bd03d25adcdb4c9653b92/src/utils/l10n-pseudo.js 6 // Which was stolen from https://hg.mozilla.org/mozilla-central/file/a1f74e8c8fb72390d22054d6b00c28b1a32f6c43/intl/l10n/L10nRegistry.jsm#l425 7 8 /** 9 * Pseudolocalizations 10 * 11 * PSEUDO_STRATEGIES is a dict of strategies to be used to modify a 12 * context in order to create pseudolocalizations. These can be used by 13 * developers to test the localizability of their code without having to 14 * actually speak a foreign language. 15 * 16 * Currently, the following pseudolocales are supported: 17 * 18 * accented - Ȧȧƈƈḗḗƞŧḗḗḓ Ḗḗƞɠŀīīşħ 19 * 20 * In Accented English all Latin letters are replaced by accented 21 * Unicode counterparts which don't impair the readability of the content. 22 * This allows developers to quickly test if any given string is being 23 * correctly displayed in its 'translated' form. Additionally, simple 24 * heuristics are used to make certain words longer to better simulate the 25 * experience of international users. 26 * 27 * bidi - ɥsıʅƃuƎ ıpıԐ 28 * 29 * Bidi English is a fake RTL locale. All words are surrounded by 30 * Unicode formatting marks forcing the RTL directionality of characters. 31 * In addition, to make the reversed text easier to read, individual 32 * letters are flipped. 33 * 34 * Note: The name above is hardcoded to be RTL in case code editors have 35 * trouble with the RLO and PDF Unicode marks. In reality, it should be 36 * surrounded by those marks as well. 37 * 38 * See https://bugzil.la/1450781 for more information. 39 * 40 * In this implementation we use code points instead of inline unicode characters 41 * because the encoding of JSM files mangles them otherwise. 42 */ 43 44 const ACCENTED_MAP = { 45 // ȦƁƇḒḖƑƓĦĪĴĶĿḾȠǾƤɊŘŞŦŬṼẆẊẎẐ 46 // prettier-ignore 47 "caps": [550, 385, 391, 7698, 7702, 401, 403, 294, 298, 308, 310, 319, 7742, 544, 510, 420, 586, 344, 350, 358, 364, 7804, 7814, 7818, 7822, 7824], 48 // ȧƀƈḓḗƒɠħīĵķŀḿƞǿƥɋřşŧŭṽẇẋẏẑ 49 // prettier-ignore 50 "small": [551, 384, 392, 7699, 7703, 402, 608, 295, 299, 309, 311, 320, 7743, 414, 511, 421, 587, 345, 351, 359, 365, 7805, 7815, 7819, 7823, 7825], 51 }; 52 53 const FLIPPED_MAP = { 54 // ∀ԐↃᗡƎℲ⅁HIſӼ⅂WNOԀÒᴚS⊥∩ɅMX⅄Z 55 // prettier-ignore 56 "caps": [8704, 1296, 8579, 5601, 398, 8498, 8513, 72, 73, 383, 1276, 8514, 87, 78, 79, 1280, 210, 7450, 83, 8869, 8745, 581, 77, 88, 8516, 90], 57 // ɐqɔpǝɟƃɥıɾʞʅɯuodbɹsʇnʌʍxʎz 58 // prettier-ignore 59 "small": [592, 113, 596, 112, 477, 607, 387, 613, 305, 638, 670, 645, 623, 117, 111, 100, 98, 633, 115, 647, 110, 652, 653, 120, 654, 122], 60 }; 61 62 function transformString( 63 map = FLIPPED_MAP, 64 elongate = false, 65 prefix = "", 66 postfix = "", 67 msg 68 ) { 69 // Exclude access-keys and other single-char messages 70 if (msg.length === 1) { 71 return msg; 72 } 73 // XML entities (‪) and XML tags. 74 const reExcluded = /(&[#\w]+;|<\s*.+?\s*>)/; 75 76 const parts = msg.split(reExcluded); 77 const modified = parts.map(part => { 78 if (reExcluded.test(part)) { 79 return part; 80 } 81 return ( 82 prefix + 83 part.replace(/[a-z]/gi, ch => { 84 const cc = ch.charCodeAt(0); 85 if (cc >= 97 && cc <= 122) { 86 const newChar = String.fromCodePoint(map.small[cc - 97]); 87 // duplicate "a", "e", "o" and "u" to emulate ~30% longer text 88 if ( 89 elongate && 90 (cc === 97 || cc === 101 || cc === 111 || cc === 117) 91 ) { 92 return newChar + newChar; 93 } 94 return newChar; 95 } 96 if (cc >= 65 && cc <= 90) { 97 return String.fromCodePoint(map.caps[cc - 65]); 98 } 99 return ch; 100 }) + 101 postfix 102 ); 103 }); 104 return modified.join(""); 105 } 106 107 export const PSEUDO_STRATEGY_TRANSFORMS = { 108 accented: transformString.bind(null, ACCENTED_MAP, true, "", ""), 109 bidi: transformString.bind(null, FLIPPED_MAP, false, "\u202e", "\u202c"), 110 };