/
locale_plugin.ts
85 lines (80 loc) 路 3.33 KB
/
locale_plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NodePath, PluginObj} from '@babel/core';
import {LogicalExpression, MemberExpression, stringLiteral} from '@babel/types';
import {TranslatePluginOptions, isLocalize} from './source_file_utils';
/**
* This Babel plugin will replace the following code forms with a string literal containing the
* given `locale`.
*
* * `$localize.locale` -> `"locale"`
* * `typeof $localize !== "undefined" && $localize.locale` -> `"locale"`
* * `xxx && typeof $localize !== "undefined" && $localize.locale` -> `"xxx && locale"`
* * `$localize.locale || default` -> `"locale" || default`
*
* @param locale The name of the locale to inline into the code.
* @param options Additional options including the name of the `$localize` function.
*/
export function makeLocalePlugin(
locale: string, {localizeName = '$localize'}: TranslatePluginOptions = {}): PluginObj {
return {
visitor: {
MemberExpression(expression: NodePath<MemberExpression>) {
const obj = expression.get('object');
if (!isLocalize(obj, localizeName)) {
return;
}
const property = expression.get('property') as NodePath;
if (!property.isIdentifier({name: 'locale'})) {
return;
}
// Check for the `$localize.locale` being guarded by a check on the existence of
// `$localize`.
const parent = expression.parentPath;
if (parent.isLogicalExpression({operator: '&&'}) && parent.get('right') === expression) {
const left = parent.get('left');
if (isLocalizeGuard(left, localizeName)) {
// Replace `typeof $localize !== "undefined" && $localize.locale` with
// `$localize.locale`
parent.replaceWith(expression);
} else if (
left.isLogicalExpression({operator: '&&'}) &&
isLocalizeGuard(left.get('right'), localizeName)) {
// The `$localize` is part of a preceding logical AND.
// Replace XXX && typeof $localize !== "undefined" && $localize.locale` with `XXX &&
// $localize.locale`
left.replaceWith(left.get('left'));
}
}
// Replace the `$localize.locale` with the string literal
expression.replaceWith(stringLiteral(locale));
}
}
};
}
/**
* Returns true if the expression one of:
* * `typeof $localize !== "undefined"`
* * `"undefined" !== typeof $localize`
*
* @param expression the expression to check
* @param localizeName the name of the `$localize` symbol
*/
function isLocalizeGuard(expression: NodePath, localizeName: string): boolean {
if (!expression.isBinaryExpression({operator: '!=='})) {
return false;
}
const left = expression.get('left');
const right = expression.get('right');
return (left.isUnaryExpression({operator: 'typeof'}) &&
isLocalize(left.get('argument'), localizeName) &&
right.isStringLiteral({value: 'undefined'})) ||
(right.isUnaryExpression({operator: 'typeof'}) &&
isLocalize(right.get('argument'), localizeName) &&
left.isStringLiteral({value: 'undefined'}));
}