Skip to content

Commit b2eec6b

Browse files
authored
Merge pull request #2004 from IFRCGo/chore/stricter-i18n-lint
chore(lint): mark unused string linting as error
2 parents ef93428 + 823f96c commit b2eec6b

File tree

127 files changed

+1686
-489
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+1686
-489
lines changed

app/eslint.config.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// eslint.config.js
21
// @ts-expect-error: @eslint/eslintrc has no types
32
import { FlatCompat } from '@eslint/eslintrc';
43
import js from '@eslint/js';
@@ -7,6 +6,7 @@ import tseslint from "typescript-eslint";
76
import process from 'process';
87

98
import i18nUsage from './scripts/eslint/i18n-usage';
9+
import { Linter } from 'eslint';
1010

1111
const dirname = process.cwd();
1212

@@ -106,8 +106,6 @@ const appConfigs = compat.config({
106106
'simple-import-sort/imports': 'warn',
107107
'simple-import-sort/exports': 'warn',
108108
'import-newlines/enforce': ['warn', 1],
109-
110-
// 'i18n-usage/ensure-i18n-keys-used': ['warn']
111109
},
112110
overrides: [
113111
{
@@ -145,17 +143,12 @@ const appConfigs = compat.config({
145143
],
146144
}));
147145

148-
const tseslintRecommendedRules = tseslint.configs.recommended.map((conf) => ({
149-
...(conf.rules)
150-
}));
151-
152-
const otherConfig = {
146+
const otherConfig: Linter.Config = {
153147
files: ['*.js', '*.ts', '*.cjs'],
154148
...js.configs.recommended,
155-
...tseslintRecommendedRules,
156149
};
157150

158-
const jsonConfig = {
151+
const jsonConfig: Linter.Config = {
159152
files: ['**/*.json'],
160153
language: 'json/json',
161154
rules: {
@@ -173,7 +166,7 @@ const jsonConfig = {
173166
// },
174167
// };
175168

176-
export default [
169+
const config: Linter.Config[] = [
177170
{
178171
plugins: {
179172
json,
@@ -184,4 +177,7 @@ export default [
184177
otherConfig,
185178
jsonConfig,
186179
// i18nJsonConfig,
180+
...tseslint.configs.recommended
187181
];
182+
183+
export default config;

app/scripts/eslint/i18n-usage.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ function getViewComponent(body: TSESTree.ProgramStatement[]) {
8888
return undefined;
8989
}
9090

91+
if (defaultExportDeclaration.declaration.type === AST_NODE_TYPES.FunctionDeclaration) {
92+
return defaultExportDeclaration.declaration;
93+
}
94+
9195
const defaultComponentName = defaultExportDeclaration.declaration.type === AST_NODE_TYPES.Identifier
9296
? defaultExportDeclaration.declaration.name
9397
: undefined;
@@ -106,21 +110,19 @@ function getViewComponent(body: TSESTree.ProgramStatement[]) {
106110

107111
function traverseForStringsKeyUsage(node: TSESTree.Node, stringsVarName: string): string[] {
108112
if (node?.type === AST_NODE_TYPES.MemberExpression) {
109-
if (node.object?.type !== AST_NODE_TYPES.Identifier) {
110-
return [];
111-
}
113+
if (node.object?.type === AST_NODE_TYPES.Identifier) {
114+
if (stringsVarName !== node.object.name) {
115+
return [];
116+
}
112117

113-
if (stringsVarName !== node.object.name) {
114-
return [];
115-
}
118+
const stringKey = getMemberKey(node);
116119

117-
const stringKey = getMemberKey(node);
120+
if (isNotDefined(stringKey)) {
121+
return [];
122+
}
118123

119-
if (isNotDefined(stringKey)) {
120-
return [];
124+
return [stringKey];
121125
}
122-
123-
return [stringKey];
124126
}
125127

126128
const keysToVisit = visitorKeys[node?.type];
@@ -196,7 +198,7 @@ function getUsedKeys(code: string) {
196198
return [];
197199
}
198200

199-
const usedStringKeys = viewComponent.body.body.flatMap((node) => (
201+
const usedStringKeys = ast.body.flatMap((node) => (
200202
traverseForStringsKeyUsage(
201203
node,
202204
stringsVarName,
@@ -207,7 +209,7 @@ function getUsedKeys(code: string) {
207209
}
208210

209211

210-
const plugin: ESLint.Plugin = {
212+
const i18nUsage: ESLint.Plugin = {
211213
meta: {
212214
name: 'eslint-plugin-i18n-usage',
213215
version: '0.0.1',
@@ -228,8 +230,8 @@ const plugin: ESLint.Plugin = {
228230
meta: {
229231
type: "problem",
230232
docs: {
231-
description: "Ensure all kesy in i18n.json are used in the component",
232-
recommended: false
233+
description: "Ensure all keys in i18n.json are used in the component",
234+
recommended: true
233235
},
234236
fixable: "code",
235237
schema: [],
@@ -358,4 +360,4 @@ const plugin: ESLint.Plugin = {
358360
},
359361
}
360362

361-
export default plugin;
363+
export default i18nUsage;

app/src/components/GlobalFooter/i18n.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
"strings": {
44
"footerAboutGo":"About GO",
55
"footerAboutGoDesc":"IFRC GO is a Red Cross Red Crescent platform to connect information on emergency needs with the right response.",
6-
"footerFindOutMore":"Find out more",
7-
"footerHelpfulLinks":"Helpful links",
86
"footerOpenSourceCode":"Open Source Code",
97
"footerApiDocumentation":"API Documentation",
108
"footerOtherResources":"Other Resources",

app/src/components/Navbar/i18n.json

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
11
{
22
"namespace": "common",
33
"strings": {
4-
"headerAppName":"IFRC GO",
5-
"headerMenuResources":"Resources",
64
"headerCreateAReportLabel":"Create a Report",
75
"headerDropdownNewFieldReport":"New Field Report",
86
"headerDropdownNewDrefApplication":"New DREF Application",
97
"headerDropdownNew3WActivity":"New 3W Activity",
108
"headerDropdownNewFlashUpdate":"New Flash Update",
11-
"headerDropdownCovid19IndicatorTracking":"COVID-19 Indicator Tracking",
12-
"headerDropdownCovid19NSFinancialOverview":"COVID-19 NS Financial Overview",
13-
"headerDropdownDrefApplication":"DREF Application",
149
"headerMenuHome":"Home",
15-
"headerMenuSurge":"Surge",
1610
"headerMenuThreeW":"Programmatic Partnerships",
1711
"headerMenuRiskWatch":"Risk Watch",
18-
"headerSearchLabel":"Search",
1912
"headerLogoAltText":"IFRC GO logo",
20-
"headerSearchPlaceholder":"Search",
21-
"userMenuAccess":"Access user menu",
22-
"userMenuViewAccount":"View user account",
2313
"userMenuLogin":"Login",
2414
"userMenuRegister":"Register",
2515
"userMenuPrepare":"Prepare",
@@ -35,7 +25,6 @@
3525
"userMenuCatalogueResources":"Catalogue of Resources",
3626
"userMenuStartPER":"Start PER Process",
3727
"userMenuGlobal3WProjectDescription":"The Programmatic Partnership is an innovative and ambitious three-year partnership between the IFRC, many of our member National Societies, and the European Union.",
38-
"userMenuSubmit3WProject":"Submit 3W Project",
3928
"userMenuRespondLabel":"Respond",
4029
"userMenuEmergencies":"Emergencies",
4130
"userMenuEmergenciesDescription": "Follow currently ongoing emergencies, as well as access the list of previous emergencies or IFRC-led operations.",
@@ -47,8 +36,6 @@
4736
"userMenuSubmit3WActivity":"Submit 3W Activity",
4837
"userMenuEarlyWarningDescription":"Early Warning focuses on preparatory action ahead of possible disasters and events. Use one of the following links to submit information on early warning.",
4938
"userMenuCreateEarlyActionFieldReport":"Create Early Action Field Report",
50-
"userMenuSubmitEAPActivation":"Submit EAP Activation",
51-
"userMenuSubmitEAPFinalReport":"Submit EAP Final Report",
5239
"userMenuCreateFlashUpdate":"Create Flash Update",
5340
"userMenuDrefProcessDescription":"Disaster Response Emergency Fund (DREF) is the quickest way of getting funding directly to local humanitarian actors. Use one of the links below to submit a DREF Application or an update.",
5441
"userMenuCreateDrefApplication":"Create DREF Application",

app/src/components/domain/ActiveOperationMap/i18n.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
"operationPopoverPeopleAffected": "People Targeted",
1010
"operationPopoverAmountRequested": "Amount Requested (CHF)",
1111
"operationPopoverAmountFunded": "Amount Funded (CHF)",
12-
"operationPopoverActivity": "Activity: {activity}",
13-
"operationPopoverStart": "Start: {start}",
14-
"operationPopoverEnd": "End: {end}",
1512
"operationPopoverEmpty": "No Current Operations",
1613
"operationType": "Type of Appeal",
1714
"operationFilterTypePlaceholder": "All Appeal Types",
@@ -22,12 +19,9 @@
2219
"explanationBubbleScalePoints": "Scale points by",
2320
"explanationBubblePopulationLabel": "# of people targeted",
2421
"explanationBubbleAmountLabel": "IFRC financial requirements",
25-
"explanationBubbleType": "Type",
2622
"explanationBubbleEmergencyAppeal": "Emergency appeal",
2723
"explanationBubbleDref": "DREF",
28-
"explanationBubbleEAP": "Early Action Protocol Activation",
2924
"explanationBubbleMultiple": "Multiple types",
30-
"explanationBubbleDeployments": "Deployments",
3125
"downloadMapTitle": "Ongoing operations",
3226
"operationMapProvinces": "Provinces",
3327
"operationMapClearFilters": "Clear Filters",

app/src/components/domain/DrefExportModal/i18n.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
"includePgaLabel": "Include PGA",
1212
"startExportLabel": "Start Export",
1313
"configureExportLabel": "Configure export",
14-
"drefDownloadPDFWithPGA": "Download PDF with PGA",
15-
"drefDownloadPDFwithoutPGA": "Download PDF without PGA",
1614
"drefFailureToExportMessage":"Failed to export PDF."
1715
}
1816
}

app/src/components/domain/HighlightedOperations/OperationCard/i18n.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
"strings": {
44
"operationCardLastUpdated": "Last updated",
55
"operationCardTargetedPopulation": "Targeted Population",
6-
"operationCardDeployedUnits": "Deployed Emergency Response Units",
76
"operationCardFunding": "Funding Requirements",
8-
"operationCardIFRCSurgePersonnel": "IFRC Surge Personnel",
9-
"operationCardNSReportingActivities": "NS Reporting Activities",
10-
"operationCardDeployed": "Deployed Surge Personnel",
117
"operationCardFundingCoverage": "{coverage}% received",
128
"operationCardFollow": "Follow",
139
"operationCardUnfollow": "Unfollow",

app/src/components/domain/OperationListItem/i18n.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"namespace": "operationListItem",
33
"strings": {
44
"operationLastUpdatedLabel": "Last updated",
5-
"operationFollowButtonLabel": "Follow",
65
"operationUnfollowButtonLabel": "Unfollow"
76
}
87
}

app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventDetails/i18n.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
"meteoSwissAuthoritativeMessage": "Please also consider {link} and classification of {classificationLink}.",
1010
"meteoSwissAuthoritativeLinkLabel": "authoritative information about the hazard",
1111
"meteoSwissTropicalStorm": "tropical storm",
12-
"meteoSwissHazardName": "{hazardType} - {hazardName}",
1312
"meteoSwissImpactValue": "{value} ({fivePercent} - {ninetyFivePercent}) {unit}",
1413
"beta": "beta",
1514
"impactLabel": "{label} {beta}",

app/src/components/domain/RiskSeasonalMap/i18n.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
"riskCategoryVeryHigh": "Very High",
1818
"riskSeasonalMapHeading": "Risk Map",
1919
"riskSeasonalCountriesByRiskHeading": "Countries by Risk",
20-
"riskPopupLabel": "Risk",
2120
"riskDataNotAvailable": "Data not available for selected filters"
2221
}
2322
}

0 commit comments

Comments
 (0)