Skip to content

Commit 48e0e5a

Browse files
Merge pull request #1 from flycode-org/feature/t-function-support
Add support for t function
2 parents 440bfce + 7ba135f commit 48e0e5a

File tree

2 files changed

+138
-46
lines changed

2 files changed

+138
-46
lines changed

src/rules/valid-key.spec.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ ruleTester.run("valid-key", rule, {
3939
code: `<Trans i18nKey="nested.valid" />`,
4040
settings: NESTED_SETTINGS,
4141
},
42+
{
43+
code: `t("valid")`,
44+
settings: FLAT_SETTINGS,
45+
},
46+
{
47+
code: `t("nested.valid")`,
48+
settings: NESTED_SETTINGS,
49+
},
4250
],
4351
invalid: [
4452
{
@@ -110,5 +118,64 @@ ruleTester.run("valid-key", rule, {
110118
},
111119
],
112120
},
121+
{
122+
code: `t(dynamicKey)`,
123+
settings: FLAT_SETTINGS,
124+
errors: [
125+
{
126+
messageId: "dynamic-key",
127+
data: { filePath: "test/fixtures/flat/en-US.json" },
128+
},
129+
],
130+
},
131+
{
132+
code: `t(42)`,
133+
settings: FLAT_SETTINGS,
134+
errors: [
135+
{
136+
messageId: "wrong-key-type",
137+
data: { filePath: "test/fixtures/flat/en-US.json" },
138+
},
139+
],
140+
},
141+
{
142+
code: `t("invalid")`,
143+
settings: FLAT_SETTINGS,
144+
errors: [
145+
{
146+
messageId: "non-existing-key",
147+
data: {
148+
key: "invalid",
149+
closestKey: "valid",
150+
},
151+
},
152+
],
153+
},
154+
{
155+
code: `t("nested.invalid")`,
156+
settings: NESTED_SETTINGS,
157+
errors: [
158+
{
159+
messageId: "non-existing-key",
160+
data: {
161+
key: "nested.invalid",
162+
closestKey: "nested.valid",
163+
},
164+
},
165+
],
166+
},
167+
{
168+
code: `t("onlyInEn")`,
169+
settings: FLAT_SETTINGS,
170+
errors: [
171+
{
172+
messageId: "missing-key-in-file",
173+
data: {
174+
key: "onlyInEn",
175+
filePath: "test/fixtures/flat/es-ES.json",
176+
},
177+
},
178+
],
179+
},
113180
],
114181
});

src/rules/valid-key.ts

Lines changed: 71 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,62 @@ export default createRule<Options, keyof typeof MESSAGES>({
5454
);
5555
const keysArray = Array.from(keys);
5656

57+
const validateStaticValue = (
58+
node: TSESTree.Node,
59+
staticValue: {
60+
value: unknown;
61+
} | null
62+
) => {
63+
if (!staticValue) {
64+
context.report({
65+
messageId: "dynamic-key",
66+
node,
67+
});
68+
return;
69+
}
70+
71+
if (typeof staticValue.value !== "string") {
72+
context.report({
73+
messageId: "wrong-key-type",
74+
node,
75+
});
76+
return;
77+
}
78+
79+
const key = staticValue.value;
80+
81+
if (!keys.has(key)) {
82+
context.report({
83+
messageId: "non-existing-key",
84+
node,
85+
data: {
86+
key,
87+
closestKey: closest(key, keysArray),
88+
},
89+
});
90+
return;
91+
}
92+
93+
for (const [filePath, translation] of Object.entries(translations)) {
94+
if (
95+
!hasKeyInTranslation(
96+
settings.translationFiles.format,
97+
translation,
98+
key
99+
)
100+
) {
101+
context.report({
102+
messageId: "missing-key-in-file",
103+
node,
104+
data: {
105+
key,
106+
filePath,
107+
},
108+
});
109+
}
110+
}
111+
};
112+
57113
return {
58114
JSXElement: (element) => {
59115
if (isTransElement(element)) {
@@ -79,54 +135,23 @@ export default createRule<Options, keyof typeof MESSAGES>({
79135
context.getScope()
80136
);
81137

82-
if (!staticValue) {
83-
context.report({
84-
messageId: "dynamic-key",
85-
node: attribute,
86-
});
87-
return;
88-
}
89-
90-
if (typeof staticValue.value !== "string") {
91-
context.report({
92-
messageId: "wrong-key-type",
93-
node: attribute,
94-
});
95-
return;
96-
}
97-
98-
const key = staticValue.value;
99-
100-
if (!keys.has(key)) {
101-
context.report({
102-
messageId: "non-existing-key",
103-
node: attribute,
104-
data: {
105-
key,
106-
closestKey: closest(key, keysArray),
107-
},
108-
});
138+
validateStaticValue(attribute, staticValue);
139+
}
140+
},
141+
CallExpression: (expression) => {
142+
if (
143+
ASTUtils.isIdentifier(expression.callee) &&
144+
expression.callee.name === "t"
145+
) {
146+
if (!expression.arguments.length) {
109147
return;
110148
}
111-
112-
for (const [filePath, translation] of Object.entries(translations)) {
113-
if (
114-
!hasKeyInTranslation(
115-
settings.translationFiles.format,
116-
translation,
117-
key
118-
)
119-
) {
120-
context.report({
121-
messageId: "missing-key-in-file",
122-
node: attribute,
123-
data: {
124-
key,
125-
filePath,
126-
},
127-
});
128-
}
129-
}
149+
const [firstArgument] = expression.arguments;
150+
const staticValue = ASTUtils.getStaticValue(
151+
firstArgument,
152+
context.getScope()
153+
);
154+
validateStaticValue(firstArgument, staticValue);
130155
}
131156
},
132157
};

0 commit comments

Comments
 (0)