I18n: Move eslint rule to package (#105860)

pull/106209/head
Tom Ratcliffe 4 weeks ago committed by GitHub
parent 1de0cd5d68
commit abb885c585
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .betterer.eslint.config.js
  2. 6
      eslint.config.js
  3. 181
      packages/grafana-eslint-rules/README.md
  4. 4
      packages/grafana-eslint-rules/index.cjs
  5. 4
      packages/grafana-i18n/package.json
  6. 185
      packages/grafana-i18n/src/eslint/README.md
  7. 9
      packages/grafana-i18n/src/eslint/index.cjs
  8. 2
      packages/grafana-i18n/src/eslint/no-translation-top-level/no-translation-top-level.cjs
  9. 34
      packages/grafana-i18n/src/eslint/no-translation-top-level/no-translation-top-level.test.js
  10. 7
      packages/grafana-i18n/src/eslint/no-untranslated-strings/no-untranslated-strings.cjs
  11. 43
      packages/grafana-i18n/src/eslint/no-untranslated-strings/no-untranslated-strings.test.js
  12. 0
      packages/grafana-i18n/src/eslint/no-untranslated-strings/translation-utils.cjs
  13. 1
      packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx
  14. 2
      packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx
  15. 2
      packages/grafana-ui/src/components/DataSourceSettings/TLSAuthSettings.tsx
  16. 4
      packages/grafana-ui/src/components/ThemeDemos/BorderRadius.tsx
  17. 2
      packages/grafana-ui/src/components/ThemeDemos/EmotionPerfTest.tsx
  18. 2
      packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.tsx
  19. 2
      packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx
  20. 2
      packages/grafana-ui/src/options/builder/axis.tsx
  21. 2
      public/app/core/components/AppChrome/History/HistoryWrapper.tsx
  22. 2
      public/app/features/actions/ActionVariablesEditor.tsx
  23. 4
      public/app/features/admin/UpgradePage.tsx
  24. 8
      public/app/features/admin/ldap/LdapDrawer.tsx
  25. 1
      public/app/features/alerting/unified/components/expressions/Expression.tsx
  26. 2
      public/app/features/alerting/unified/components/notification-policies/PromDurationDocs.tsx
  27. 16
      public/app/features/alerting/unified/components/receivers/editor/templateDataSuggestions.ts
  28. 2
      public/app/features/alerting/unified/components/receivers/form/fields/SubformArrayField.tsx
  29. 2
      public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.tsx
  30. 4
      public/app/features/alerting/unified/components/rule-editor/GroupAndNamespaceFields.tsx
  31. 4
      public/app/features/alerting/unified/components/rules/RuleDetails.tsx
  32. 2
      public/app/features/alerting/unified/components/rules/RulesTable.tsx
  33. 2
      public/app/features/alerting/unified/components/silences/SilencesFilter.tsx
  34. 2
      public/app/features/alerting/unified/components/silences/SilencesTable.tsx
  35. 1
      public/app/features/alerting/unified/testSetup/plugins.ts
  36. 8
      public/app/features/auth-config/fields.tsx
  37. 3
      public/app/features/canvas/runtime/ables.tsx
  38. 2
      public/app/features/canvas/runtime/frame.tsx
  39. 1
      public/app/features/commandPalette/ResultItem.tsx
  40. 4
      public/app/features/commandPalette/actions/staticActions.ts
  41. 2
      public/app/features/correlations/Forms/ConfigureCorrelationSourceForm.tsx
  42. 2
      public/app/features/correlations/Forms/TransformationEditorRow.tsx
  43. 2
      public/app/features/dashboard-scene/embedding/EmbeddedDashboardTestPage.tsx
  44. 1
      public/app/features/dashboard-scene/settings/variables/VariableSetEditableElement.tsx
  45. 2
      public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.tsx
  46. 2
      public/app/features/dashboard-scene/settings/variables/components/DataSourceVariableForm.tsx
  47. 4
      public/app/features/dashboard-scene/settings/variables/components/IntervalVariableForm.tsx
  48. 2
      public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx
  49. 2
      public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx
  50. 2
      public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx
  51. 2
      public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx
  52. 2
      public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx
  53. 2
      public/app/features/dimensions/editors/ResourceDimensionEditor.tsx
  54. 5
      public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx
  55. 10
      public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx
  56. 2
      public/app/features/explore/ExploreRunQueryButton.tsx
  57. 6
      public/app/features/explore/Logs/LogsMetaRow.tsx
  58. 4
      public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx
  59. 4
      public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.tsx
  60. 6
      public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianLogs.tsx
  61. 6
      public/app/features/explore/extensions/getExploreExtensionConfigs.tsx
  62. 2
      public/app/features/invites/SignupInvited.tsx
  63. 2
      public/app/features/manage-dashboards/DashboardImportPage.tsx
  64. 2
      public/app/features/migrate-to-cloud/shared/AlertWithTraceID.tsx
  65. 2
      public/app/features/org/UserInviteForm.tsx
  66. 2
      public/app/features/plugins/admin/components/PluginDetailsPanel.tsx
  67. 4
      public/app/features/plugins/components/PluginPageContext.tsx
  68. 2
      public/app/features/plugins/extensions/utils.tsx
  69. 11
      public/app/features/provisioning/Shared/TokenPermissionsInfo.tsx
  70. 1
      public/app/features/provisioning/Wizard/ProvisioningWizard.tsx
  71. 1
      public/app/features/query/components/QueryEditorRowHeader.tsx
  72. 12
      public/app/features/query/components/QueryGroupOptions.tsx
  73. 2
      public/app/features/sandbox/TestStuffPage.tsx
  74. 2
      public/app/features/teams/CreateTeam.tsx
  75. 2
      public/app/features/teams/TeamSettings.tsx
  76. 7
      public/app/features/transformers/editors/CalculateFieldTransformerEditor/UnaryOperationEditor.tsx
  77. 6
      public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx
  78. 2
      public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx
  79. 2
      public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx
  80. 4
      public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx
  81. 1
      public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx
  82. 2
      public/app/features/variables/interval/reducer.ts
  83. 2
      public/app/features/visualization/data-hover/DataHoverRows.tsx
  84. 6
      public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AppRegistrationCredentials.tsx
  85. 2
      public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.tsx
  86. 2
      public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.tsx
  87. 8
      public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.tsx
  88. 12
      public/app/plugins/datasource/mssql/CheatSheet.tsx
  89. 6
      public/app/plugins/datasource/mssql/azureauth/AzureCredentialsForm.tsx
  90. 6
      public/app/plugins/datasource/mssql/configuration/ConfigurationEditor.tsx
  91. 10
      public/app/plugins/datasource/mssql/configuration/Kerberos.tsx
  92. 1
      public/locales/en-US/grafana.json
  93. 2
      public/swagger/SwaggerPage.tsx

@ -10,6 +10,7 @@ const testingLibraryPlugin = require('eslint-plugin-testing-library');
const grafanaConfig = require('@grafana/eslint-config/flat');
const grafanaPlugin = require('@grafana/eslint-plugin');
const grafanaI18nPlugin = require('@grafana/i18n/eslint-plugin');
// Include the Grafana config and remove the rules,
// as we just want to pull in all of the necessary configuration but not run the rules
@ -65,6 +66,7 @@ module.exports = [
'no-barrel-files': barrelPlugin,
'@grafana': grafanaPlugin,
'testing-library': testingLibraryPlugin,
'@grafana/i18n': grafanaI18nPlugin,
},
linterOptions: {
// This reports unused disable directives that we can clean up but

@ -13,6 +13,7 @@ const unicornPlugin = require('eslint-plugin-unicorn');
const grafanaConfig = require('@grafana/eslint-config/flat');
const grafanaPlugin = require('@grafana/eslint-plugin');
const grafanaI18nPlugin = require('@grafana/i18n/eslint-plugin');
const bettererConfig = require('./.betterer.eslint.config');
const getEnvConfig = require('./scripts/webpack/env-util');
@ -294,6 +295,7 @@ module.exports = [
name: 'grafana/i18n-overrides',
plugins: {
'@grafana': grafanaPlugin,
'@grafana/i18n': grafanaI18nPlugin,
},
files: [
'public/app/!(plugins)/**/*.{ts,tsx,js,jsx}',
@ -308,8 +310,8 @@ module.exports = [
'**/mock*.{ts,tsx}',
],
rules: {
'@grafana/no-untranslated-strings': ['error', { calleesToIgnore: ['^css$', 'use[A-Z].*'] }],
'@grafana/no-translation-top-level': 'error',
'@grafana/i18n/no-untranslated-strings': ['error', { calleesToIgnore: ['^css$', 'use[A-Z].*'] }],
'@grafana/i18n/no-translation-top-level': 'error',
},
},
{

@ -111,184 +111,3 @@ const getStyles = (theme: GrafanaTheme2) => ({
### `theme-token-usage`
Used to find all instances of `theme` tokens being used in the codebase and emit the counts as metrics. Should **not** be used as an actual lint rule!
### `no-untranslated-strings`
Check if strings are marked for translation inside JSX Elements, in certain JSX props, and in certain object properties.
### Options
#### `forceFix`
Allows specifying directories that, if the file is present within, then the rule will automatically fix the errors. This is primarily a workaround to allow for automatic mark up of new violations as the rule evolves.
#### Example:
```ts
{
'@grafana/no-untranslated-strings': ['error', { forceFix: ['app/features/some-feature'] }],
}
```
#### `calleesToIgnore`
Allows specifying regexes for methods that should be ignored when checking if object properties are untranslated.
This is particularly useful to exclude references to properties such as `label` inside `css()` calls.
#### Example:
```ts
{
'@grafana/no-untranslated-strings': ['error', { calleesToIgnore: ['^css$'] }],
}
// The below would not be reported as an error
const foo = css({
label: 'test',
});
// The below would still be reported as an error
const bar = {
label: 'test',
};
```
#### JSXText
```tsx
// Bad ❌
<InlineToast placement="top" referenceElement={buttonRef.current}>
Copied
</InlineToast>
// Good ✅
<InlineToast placement="top" referenceElement={buttonRef.current}>
<Trans i18nKey="clipboard-button.inline-toast.success">Copied</Trans>
</InlineToast>
```
#### JSXAttributes
```tsx
// Bad ❌
<div title="foo bar" />
// Good ✅
<div title={t('some.key.foo-bar', 'foo bar')} />
```
#### Object properties
```tsx
// Bad ❌
const someConfig = {
label: 'Some label',
};
// Good ✅
const getSomeConfig = () => ({
label: t('some.key.label', 'Some label'),
});
```
#### Passing variables to translations
```tsx
// Bad ❌
const SearchTitle = ({ term }) => <div>Results for {term}</div>;
// Good ✅
const SearchTitle = ({ term }) => <Trans i18nKey="search-page.results-title">Results for {{ term }}</Trans>;
// Good ✅ (if you need to interpolate variables inside nested components)
const SearchTerm = ({ term }) => <Text color="success">{term}</Text>;
const SearchTitle = ({ term }) => (
<Trans i18nKey="search-page.results-title">
Results for <SearchTerm term={term} />
</Trans>
);
// Good ✅ (if you need to interpolate variables and additional translated strings inside nested components)
const SearchTitle = ({ term }) => (
<Trans i18nKey="search-page.results-title" values={{ myVariable: term }}>
Results for <Text color="success">{'{{ myVariable }}'} and this translated text is also in green</Text>
</Trans>
);
```
#### How to translate props or attributes
This rule checks if a string is wrapped up by the `Trans` tag, or if certain props contain untranslated strings.
We ask for such props to be translated with the `t()` function.
The below props are checked for untranslated strings:
- `label`
- `description`
- `placeholder`
- `aria-label`
- `title`
- `subTitle`
- `text`
- `tooltip`
- `message`
- `name`
```tsx
// Bad ❌
<input type="value" placeholder={'Username'} />;
// Good ✅
const placeholder = t('form.username-placeholder', 'Username');
return <input type="value" placeholder={placeholder} />;
```
Check more info about how translations work in Grafana in [Internationalization.md](https://github.com/grafana/grafana/blob/main/contribute/internationalization.md)
### `no-translation-top-level`
Ensure that `t()` translation method is not used at the top level of a file, outside of a component of method.
This is to prevent calling the translation method before it's been instantiated.
This does not cause an error if a file is lazily loaded, but refactors can cause errors, and it can cause problems in tests.
Fix the
```tsx
// Bad ❌
const someTranslatedText = t('some.key', 'Some text');
const SomeComponent = () => {
return <div title={someTranslatedText} />;
};
// Good ✅
const SomeComponent = () => {
const someTranslatedText = t('some.key', 'Some text');
return <div title={someTranslatedText} />;
};
// Bad ❌
const someConfigThatHasToBeShared = [{ foo: t('some.key', 'Some text') }];
const SomeComponent = () => {
return (
<div>
{someConfigThatHasToBeShared.map((cfg) => {
return <div>{cfg.foo}</div>;
})}
</div>
);
};
// Good ✅
const someConfigThatHasToBeShared = () => [{ foo: t('some.key', 'Some text') }];
const SomeComponent = () => {
const configs = someConfigThatHasToBeShared();
return (
<div>
{configs.map((cfg) => {
return <div>{cfg.foo}</div>;
})}
</div>
);
};
```

@ -1,8 +1,6 @@
const noAriaLabelSelectors = require('./rules/no-aria-label-e2e-selectors.cjs');
const noBorderRadiusLiteral = require('./rules/no-border-radius-literal.cjs');
const noUnreducedMotion = require('./rules/no-unreduced-motion.cjs');
const noUntranslatedStrings = require('./rules/no-untranslated-strings.cjs');
const noTranslationTopLevel = require('./rules/no-translation-top-level.cjs');
const themeTokenUsage = require('./rules/theme-token-usage.cjs');
const noRestrictedImgSrcs = require('./rules/no-restricted-img-srcs.cjs');
@ -12,8 +10,6 @@ module.exports = {
'no-aria-label-selectors': noAriaLabelSelectors,
'no-border-radius-literal': noBorderRadiusLiteral,
'theme-token-usage': themeTokenUsage,
'no-untranslated-strings': noUntranslatedStrings,
'no-translation-top-level': noTranslationTopLevel,
'no-restricted-img-srcs': noRestrictedImgSrcs,
},
};

@ -26,6 +26,10 @@
"./internal": {
"import": "./src/internal/index.ts",
"require": "./src/internal/index.ts"
},
"./eslint-plugin": {
"import": "./src/eslint/index.cjs",
"require": "./src/eslint/index.cjs"
}
},
"publishConfig": {

@ -0,0 +1,185 @@
# Grafana Internationalization ESLint Rules
This package also contains custom i18n eslint rules for use within the Grafana codebase and plugins.
## Rules
### `no-untranslated-strings`
Check if strings are marked for translation inside JSX Elements, in certain JSX props, and in certain object properties.
### Options
#### `forceFix`
Allows specifying directories that, if the file is present within, then the rule will automatically fix the errors. This is primarily a workaround to allow for automatic mark up of new violations as the rule evolves.
#### Example:
```ts
{
'@grafana/i18n/no-untranslated-strings': ['error', { forceFix: ['app/features/some-feature'] }],
}
```
#### `calleesToIgnore`
Allows specifying regexes for methods that should be ignored when checking if object properties are untranslated.
This is particularly useful to exclude references to properties such as `label` inside `css()` calls.
#### Example:
```ts
{
'@grafana/i18n/no-untranslated-strings': ['error', { calleesToIgnore: ['^css$'] }],
}
// The below would not be reported as an error
const foo = css({
label: 'test',
});
// The below would still be reported as an error
const bar = {
label: 'test',
};
```
#### JSXText
```tsx
// Bad ❌
<InlineToast placement="top" referenceElement={buttonRef.current}>
Copied
</InlineToast>
// Good ✅
<InlineToast placement="top" referenceElement={buttonRef.current}>
<Trans i18nKey="clipboard-button.inline-toast.success">Copied</Trans>
</InlineToast>
```
#### JSXAttributes
```tsx
// Bad ❌
<div title="foo bar" />
// Good ✅
<div title={t('some.key.foo-bar', 'foo bar')} />
```
#### Object properties
```tsx
// Bad ❌
const someConfig = {
label: 'Some label',
};
// Good ✅
const getSomeConfig = () => ({
label: t('some.key.label', 'Some label'),
});
```
#### Passing variables to translations
```tsx
// Bad ❌
const SearchTitle = ({ term }) => <div>Results for {term}</div>;
// Good ✅
const SearchTitle = ({ term }) => <Trans i18nKey="search-page.results-title">Results for {{ term }}</Trans>;
// Good ✅ (if you need to interpolate variables inside nested components)
const SearchTerm = ({ term }) => <Text color="success">{term}</Text>;
const SearchTitle = ({ term }) => (
<Trans i18nKey="search-page.results-title">
Results for <SearchTerm term={term} />
</Trans>
);
// Good ✅ (if you need to interpolate variables and additional translated strings inside nested components)
const SearchTitle = ({ term }) => (
<Trans i18nKey="search-page.results-title" values={{ myVariable: term }}>
Results for <Text color="success">{'{{ myVariable }}'} and this translated text is also in green</Text>
</Trans>
);
```
#### How to translate props or attributes
This rule checks if a string is wrapped up by the `Trans` tag, or if certain props contain untranslated strings.
We ask for such props to be translated with the `t()` function.
The below props are checked for untranslated strings:
- `label`
- `description`
- `placeholder`
- `aria-label`
- `title`
- `subTitle`
- `text`
- `tooltip`
- `message`
- `name`
```tsx
// Bad ❌
<input type="value" placeholder={'Username'} />;
// Good ✅
const placeholder = t('form.username-placeholder', 'Username');
return <input type="value" placeholder={placeholder} />;
```
Check more info about how translations work in Grafana in [Internationalization.md](https://github.com/grafana/grafana/blob/main/contribute/internationalization.md)
### `no-translation-top-level`
Ensure that `t()` translation method is not used at the top level of a file, outside of a component of method.
This is to prevent calling the translation method before it's been instantiated.
This does not cause an error if a file is lazily loaded, but refactors can cause errors, and it can cause problems in tests.
```tsx
// Bad ❌
const someTranslatedText = t('some.key', 'Some text');
const SomeComponent = () => {
return <div title={someTranslatedText} />;
};
// Good ✅
const SomeComponent = () => {
const someTranslatedText = t('some.key', 'Some text');
return <div title={someTranslatedText} />;
};
// Bad ❌
const someConfigThatHasToBeShared = [{ foo: t('some.key', 'Some text') }];
const SomeComponent = () => {
return (
<div>
{someConfigThatHasToBeShared.map((cfg) => {
return <div>{cfg.foo}</div>;
})}
</div>
);
};
// Good ✅
const getSomeConfigThatHasToBeShared = () => [{ foo: t('some.key', 'Some text') }];
const SomeComponent = () => {
const configs = getSomeConfigThatHasToBeShared();
return (
<div>
{configs.map((cfg) => {
return <div>{cfg.foo}</div>;
})}
</div>
);
};
```

@ -0,0 +1,9 @@
const noUntranslatedStrings = require('./no-untranslated-strings/no-untranslated-strings.cjs');
const noTranslationTopLevel = require('./no-translation-top-level/no-translation-top-level.cjs');
module.exports = {
rules: {
'no-untranslated-strings': noUntranslatedStrings,
'no-translation-top-level': noTranslationTopLevel,
},
};

@ -7,7 +7,7 @@ const { ESLintUtils, AST_NODE_TYPES } = require('@typescript-eslint/utils');
*/
const createRule = ESLintUtils.RuleCreator(
(name) => `https://github.com/grafana/grafana/blob/main/packages/grafana-eslint-rules/README.md#${name}`
(name) => `https://github.com/grafana/grafana/blob/main/packages/grafana-i18n/src/eslint/README.md#${name}`
);
/**

@ -1,8 +1,8 @@
import { RuleTester } from 'eslint';
import noTranslationTopLevel from '../rules/no-translation-top-level.cjs';
import noTranslationTopLevel from './no-translation-top-level.cjs';
RuleTester.setDefaultConfig({
const ruleTester = new RuleTester({
languageOptions: {
ecmaVersion: 2018,
sourceType: 'module',
@ -14,13 +14,11 @@ RuleTester.setDefaultConfig({
},
});
const expectedErrorMessage = 'Do not use the t() function outside of a component or function';
const ruleTester = new RuleTester();
// @ts-ignore
ruleTester.run('eslint no-translation-top-level', noTranslationTopLevel, {
valid: [
{
name: 'invocation inside component',
code: `
function Component() {
return <div>{t('some.key', 'Some text')}</div>;
@ -28,31 +26,37 @@ function Component() {
`,
},
{
name: 'invocation inside function',
code: `const foo = () => t('some.key', 'Some text');`,
},
{
code: `const foo = ttt('some.key', 'Some text');`,
name: 'invocation inside class component',
code: `class Component {
render() {
return t('some.key', 'Some text');
}
}`,
},
{
code: `class Component {
render() {
return t('some.key', 'Some text');
}
}`,
name: 'invocation of something not named t at top level',
code: `const foo = ttt('some.key', 'Some text');`,
},
],
invalid: [
{
name: 'invocation at top level',
code: `const thing = t('some.key', 'Some text');`,
errors: [{ message: expectedErrorMessage }],
errors: 1,
},
{
name: 'invocation in array',
code: `const things = [t('some.key', 'Some text')];`,
errors: [{ message: expectedErrorMessage }],
errors: 1,
},
{
name: 'invocation in object',
code: `const objectThings = [{foo: t('some.key', 'Some text')}];`,
errors: [{ message: expectedErrorMessage }],
errors: 1,
},
],
});

@ -18,7 +18,7 @@ const {
const { ESLintUtils, AST_NODE_TYPES } = require('@typescript-eslint/utils');
const createRule = ESLintUtils.RuleCreator(
(name) => `https://github.com/grafana/grafana/blob/main/packages/grafana-eslint-rules/README.md#${name}`
(name) => `https://github.com/grafana/grafana/blob/main/packages/grafana-i18n/src/eslint/README.md#${name}`
);
/**
@ -224,7 +224,10 @@ const noUntranslatedStrings = createRule({
// We don't want to report if the parent has a text node,
// as we'd end up doing it twice. This makes it awkward for us to auto fix
const parentHasText = parentHasChildren
? parent.children.some((child) => child.type === AST_NODE_TYPES.JSXText && getNodeValue(child).trim())
? parent.children.some((child) => {
const childValue = getNodeValue(child).trim();
return child.type === AST_NODE_TYPES.JSXText && childValue && !isStringNonAlphanumeric(childValue);
})
: false;
if (untranslatedTextNodes.length && !parentHasText) {

@ -1,8 +1,17 @@
import { RuleTester } from 'eslint';
import noUntranslatedStrings from '../rules/no-untranslated-strings.cjs';
import noUntranslatedStrings from './no-untranslated-strings.cjs';
RuleTester.setDefaultConfig({
const filename = 'public/app/features/some-feature/nested/SomeFile.tsx';
const packageName = '@grafana/i18n';
const TRANS_IMPORT = `import { Trans } from '${packageName}';`;
const T_IMPORT = `import { t } from '${packageName}/internal';`;
const USE_TRANSLATE_IMPORT = `import { useTranslate } from '${packageName}';`;
const TRANS_AND_USE_TRANSLATE_IMPORT = `import { Trans, useTranslate } from '${packageName}';`;
const ruleTester = new RuleTester({
languageOptions: {
ecmaVersion: 2018,
sourceType: 'module',
@ -14,17 +23,7 @@ RuleTester.setDefaultConfig({
},
});
const filename = 'public/app/features/some-feature/nested/SomeFile.tsx';
const packageName = '@grafana/i18n';
const TRANS_IMPORT = `import { Trans } from '${packageName}';`;
const T_IMPORT = `import { t } from '${packageName}/internal';`;
const USE_TRANSLATE_IMPORT = `import { useTranslate } from '${packageName}';`;
const TRANS_AND_USE_TRANSLATE_IMPORT = `import { Trans, useTranslate } from '${packageName}';`;
const ruleTester = new RuleTester();
//@ts-ignore
ruleTester.run('eslint no-untranslated-strings', noUntranslatedStrings, {
test: [],
valid: [
@ -212,6 +211,24 @@ const Foo = () => <div><Trans i18nKey="some-feature.foo.untranslated-text">Untra
],
},
{
name: 'non-alphanumeric characters outside child element',
code: `
const Foo = () => {
return (
<>
<div>
something untranslated but i'm a naughty dev and
I put a bunch of non-alphanumeric characters outside of the div
</div>
.?!;
</>
)
}`,
filename,
errors: 1,
},
{
name: 'Text inside JSXElement, not in a function',
code: `

@ -267,7 +267,6 @@ export const MultiCombobox = <T extends string | number>(props: MultiComboboxPro
))}
{selectedItems.length > visibleItems.length && (
<Box display="flex" direction="row" marginLeft={0.5} gap={1} ref={counterMeasureRef}>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
<Text>...</Text>
<Tooltip
interactive

@ -61,7 +61,7 @@ const CustomHeaderRow = ({ header, onBlur, onChange, onRemove, onReset }: Custom
<FormField
label={t('grafana-ui.data-source-settings.custom-headers-header', 'Header')}
name="name"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="X-Custom-Header"
labelWidth={5}
value={header.name || ''}

@ -98,7 +98,7 @@ export const TLSAuthSettings = ({ dataSourceConfig, onChange }: HttpSettingsBase
label={t('grafana-ui.data-source-settings.tls-server-name-label', 'ServerName')}
labelWidth={7}
inputWidth={30}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="domain.example.com"
value={hasServerName && dataSourceConfig.jsonData.serverName}
onChange={onServerNameLabelChange}

@ -24,14 +24,14 @@ export const BorderRadiusContainer = ({
return (
<Stack direction="column" alignItems="center" gap={4}>
<Stack alignItems="center">
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Text variant="code">getInternalRadius</Text>
<div className={styles.baseForInternal}>
<div className={styles.internalContainer} />
</div>
</Stack>
<Stack alignItems="center">
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Text variant="code">getExternalRadius</Text>
<div className={styles.externalContainer}>
<div className={styles.baseForExternal} />

@ -1,4 +1,4 @@
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
/** @jsxImportSource @emotion/react */
import { css, cx } from '@emotion/css';
import classnames from 'classnames';

@ -1,4 +1,4 @@
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
import { css, cx } from '@emotion/css';
import { useState } from 'react';
import * as React from 'react';

@ -36,7 +36,7 @@ export const UsersIndicator = ({ users, onClick, limit = 4 }: UsersIndicatorProp
{limitReached && (
<UserIcon onClick={onClick} userView={{ user: { name: 'Extra users' }, lastActiveAt: '' }} showTooltip={false}>
{tooManyUsers
? // eslint-disable-next-line @grafana/no-untranslated-strings
? // eslint-disable-next-line @grafana/i18n/no-untranslated-strings
'...'
: `+${extraUsers}`}
</UserIcon>

@ -179,7 +179,7 @@ export const ScaleDistributionEditor = ({ value, onChange }: StandardEditorProps
{type === ScaleDistribution.Symlog && (
<Field label={t('grafana-ui.axis-builder.linear-threshold', 'Linear threshold')} style={{ marginBottom: 0 }}>
<Input
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="1"
value={value?.linearThreshold}
onChange={(v) => {

@ -139,7 +139,7 @@ function HistoryEntryAppView({ entry, isSelected, onClick }: ItemProps) {
<Text key={index}>
{breadcrumb.text}{' '}
{index !== breadcrumbs.length - 1
? // eslint-disable-next-line @grafana/no-untranslated-strings
? // eslint-disable-next-line @grafana/i18n/no-untranslated-strings
'> '
: ''}
</Text>

@ -56,7 +56,7 @@ export const ActionVariablesEditor = ({ value, onChange }: Props) => {
const variableTypeOptions: ComboboxOption[] = [
{
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label: 'string',
value: ActionVariableType.String,
},

@ -200,7 +200,7 @@ const FeatureListing = () => {
</Item>
<Item title={t('admin.feature-listing.title-enterprise-plugins', 'Enterprise plugins')}>
<List nested={true}>
{/* eslint-disable @grafana/no-untranslated-strings */}
{/* eslint-disable @grafana/i18n/no-untranslated-strings */}
<Item title="Oracle" />
<Item title="Splunk" />
<Item title="Service Now" />
@ -216,7 +216,7 @@ const FeatureListing = () => {
<Item title="Salesforce" />
<Item title="Snowflake" />
<Item title="Wavefront" />
{/* eslint-enable @grafana/no-untranslated-strings */}
{/* eslint-enable @grafana/i18n/no-untranslated-strings */}
</List>
</Item>
</List>

@ -99,7 +99,7 @@ export const LdapDrawerComponent = ({
<Trans i18nKey="ldap-drawer.extra-security-section.use-ssl-tooltip">
For a complete list of supported ciphers and TLS versions, refer to:
</Trans>{' '}
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<TextLink style={{ fontSize: 'inherit' }} href="https://go.dev/src/crypto/tls/cipher_suites.go" external>
https://go.dev/src/crypto/tls/cipher_suites.go
</TextLink>
@ -145,7 +145,7 @@ export const LdapDrawerComponent = ({
>
<Input
id="port"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="389"
type="number"
{...register(`${serverConfig}.port`, { valueAsNumber: true })}
@ -160,7 +160,7 @@ export const LdapDrawerComponent = ({
>
<Input
id="timeout"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="10"
type="number"
{...register(`${serverConfig}.timeout`, { valueAsNumber: true })}
@ -414,7 +414,7 @@ export const LdapDrawerComponent = ({
<Field label={t('ldap-drawer.extra-security-section.client-cert-label', 'Client certificate path')}>
<Input
id="client-cert"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="/path/to/client_cert.pem"
type="text"
{...register(`${serverConfig}.client_cert`)}

@ -413,7 +413,6 @@ interface FrameProps extends Pick<ExpressionProps, 'isAlertCondition'> {
const OpeningBracket = () => <span>{'{'}</span>;
const ClosingBracket = () => <span>{'}'}</span>;
// eslint-disable-next-line @grafana/no-untranslated-strings
const Quote = () => <span>&quot;</span>;
const Equals = () => <span>{'='}</span>;

@ -39,7 +39,7 @@ export function PromDurationDocs() {
<div>
<Trans i18nKey="alerting.prom-duration-docs.multiple-units-combined">Multiple units combined</Trans>
</div>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<code>1m30s, 2h30m20s, 1w2d</code>
</div>
</div>

@ -17,7 +17,7 @@ import { SuggestionDefinition } from './suggestionDefinition';
export function getGlobalSuggestions(monaco: Monaco): SuggestionDefinition[] {
const kind = monaco.languages.CompletionItemKind.Field;
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
return [
{
label: 'Alerts',
@ -39,14 +39,14 @@ export function getGlobalSuggestions(monaco: Monaco): SuggestionDefinition[] {
{ label: 'GroupKey', kind, detail: 'string' },
{ label: 'TruncatedAlerts', kind, detail: 'integer' },
];
/* eslint-enable @grafana/no-untranslated-strings */
/* eslint-enable @grafana/i18n/no-untranslated-strings */
}
// Suggestions that are valid only in the scope of an alert (e.g. in the .Alerts loop)
export function getAlertSuggestions(monaco: Monaco): SuggestionDefinition[] {
const kind = monaco.languages.CompletionItemKind.Field;
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
return [
{
label: { label: 'Status', detail: '(Alert)', description: 'string' },
@ -148,26 +148,26 @@ export function getAlertSuggestions(monaco: Monaco): SuggestionDefinition[] {
),
},
];
/* eslint-enable @grafana/no-untranslated-strings */
/* eslint-enable @grafana/i18n/no-untranslated-strings */
}
// Suggestions for .Alerts
export function getAlertsSuggestions(monaco: Monaco): SuggestionDefinition[] {
const kind = monaco.languages.CompletionItemKind.Field;
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
return [
{ label: 'Firing', kind, detail: 'Alert[]' },
{ label: 'Resolved', kind, detail: 'Alert[]' },
];
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-enable @grafana/i18n/no-untranslated-strings */
}
// Suggestions for the KeyValue types
export function getKeyValueSuggestions(monaco: Monaco): SuggestionDefinition[] {
const kind = monaco.languages.CompletionItemKind.Field;
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
return [
{ label: 'SortedPairs', kind, detail: '[]KeyValue' },
{ label: 'Names', kind, detail: '[]string' },
@ -178,7 +178,7 @@ export function getKeyValueSuggestions(monaco: Monaco): SuggestionDefinition[] {
kind: monaco.languages.CompletionItemKind.Method,
},
];
/* eslint-enable @grafana/no-untranslated-strings */
/* eslint-enable @grafana/i18n/no-untranslated-strings */
}
export const snippets = {

@ -39,7 +39,7 @@ export const SubformArrayField = ({
<div className={styles.wrapper}>
<CollapsibleSection
className={styles.collapsibleSection}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label={`${option.label} (${fields.length})`}
description={option.description}
>

@ -182,7 +182,7 @@ const AnnotationsStep = () => {
{...register(`annotations.${index}.value`)}
placeholder={
isUrl
? // eslint-disable-next-line @grafana/no-untranslated-strings
? // eslint-disable-next-line @grafana/i18n/no-untranslated-strings
'https://'
: (annotationField.key &&
t('alerting.annotations-step.placeholder-value-input', 'Enter a {{key}}...', {

@ -49,7 +49,7 @@ export const GroupAndNamespaceFields = ({ rulesSourceName }: Props) => {
label={t('alerting.group-and-namespace-fields.namespace-picker-label-namespace', 'Namespace')}
// Disable translations as we don't intend to use this dropdown longterm,
// so avoiding us adding translations for the sake of it
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
description="Type to search for an existing namespace or create a new one"
error={errors.namespace?.message}
invalid={!!errors.namespace?.message}
@ -82,7 +82,7 @@ export const GroupAndNamespaceFields = ({ rulesSourceName }: Props) => {
label={t('alerting.group-and-namespace-fields.group-picker-label-group', 'Group')}
// Disable translations as we don't intend to use this dropdown longterm,
// so avoiding us adding translations for the sake of it
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
description="Type to search for an existing group or create a new one"
error={errors.group?.message}
invalid={!!errors.group?.message}

@ -118,7 +118,7 @@ const EvaluationBehaviorSummary = ({ rule }: EvaluationBehaviorSummaryProps) =>
>
<Tooltip
placement="top"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
content={`${dateTimeFormat(lastEvaluation, { format: 'YYYY-MM-DD HH:mm:ss' })}`}
theme="info"
>
@ -138,7 +138,7 @@ const EvaluationBehaviorSummary = ({ rule }: EvaluationBehaviorSummaryProps) =>
>
<Tooltip
placement="top"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
content={`${lastEvaluationDuration}s`}
theme="info"
>

@ -268,7 +268,7 @@ function useColumns(
nextEvalInfo && (
<Tooltip
placement="top"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
content={`${nextEvalInfo?.fullDate}`}
theme="info"
>

@ -59,7 +59,7 @@ export const SilencesFilter = () => {
</Trans>
</div>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<pre>severity=critical, env=production</pre>
</>
}

@ -332,7 +332,7 @@ function useColumns(alertManagerSourceName: string) {
<span data-testid="alerts">
{Array.isArray(silencedAlerts)
? silencedAlerts.length
: // eslint-disable-next-line @grafana/no-untranslated-strings
: // eslint-disable-next-line @grafana/i18n/no-untranslated-strings
'-'}
</span>
);

@ -1,4 +1,3 @@
/* eslint-disable @grafana/no-untranslated-strings */
import { PluginLoadingStrategy, PluginMeta, PluginType } from '@grafana/data';
import { AppPluginConfig, setPluginComponentsHook, setPluginLinksHook } from '@grafana/runtime';
import { SupportedPlugin } from 'app/features/alerting/unified/types/pluginBridges';

@ -433,13 +433,13 @@ export function fieldMap(provider: string): Record<string, FieldData> {
),
multi: false,
options: [
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
{ value: 'AutoDetect', label: 'AutoDetect' },
{ value: 'InParams', label: 'InParams' },
{ value: 'InHeader', label: 'InHeader' },
],
defaultValue: { value: 'AutoDetect', label: 'AutoDetect' },
/* eslint-enable @grafana/no-untranslated-strings */
/* eslint-enable @grafana/i18n/no-untranslated-strings */
},
tokenUrl: {
label: tokenURLLabel,
@ -914,7 +914,7 @@ function orgMappingDescription(provider: string): string {
function clientAuthenticationOptions(provider: string): Array<SelectableValue<string>> {
// Other options are purposefully not translated
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
switch (provider) {
case 'azuread':
return [
@ -930,5 +930,5 @@ function clientAuthenticationOptions(provider: string): Array<SelectableValue<st
{ value: 'client_secret_post', label: 'Client secret' },
];
}
/* eslint-enable @grafana/no-untranslated-strings */
/* eslint-enable @grafana/i18n/no-untranslated-strings */
}

@ -34,7 +34,6 @@ export const settingsViewable = (scene: Scene) => ({
const rect = moveable.getRect();
return (
// eslint-disable-next-line @grafana/no-untranslated-strings
<div
key={'settings-viewable'}
className={'moveable-settings'}
@ -70,7 +69,7 @@ export const dimensionViewable = {
render(moveable: MoveableManagerInterface<unknown, unknown>, React: Renderer) {
const rect = moveable.getRect();
return (
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
<div
key={'dimension-viewable'}
className={'moveable-dimension'}

@ -29,7 +29,7 @@ export const frameItemDummy: CanvasElementItem = {
display: () => {
// never shown to end user
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
return <div>FRAME!</div>;
},
};

@ -54,7 +54,6 @@ export const ResultItem = React.forwardRef(
{!hasCommandOrLink(ancestor) && (
<>
<span className={styles.breadcrumbAncestor}>{ancestor.name}</span>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
<span className={styles.breadcrumbSeparator}>&rsaquo;</span>
</>
)}

@ -103,7 +103,7 @@ function getGlobalActions(): CommandPaletteAction[] {
];
if (process.env.NODE_ENV === 'development') {
// eslint-disable @grafana/no-untranslated-strings
// eslint-disable @grafana/i18n/no-untranslated-strings
const section = 'Dev tooling';
const currentState = currentMockApiState();
const mockApiAction = currentState ? 'Disable' : 'Enable';
@ -128,7 +128,7 @@ function getGlobalActions(): CommandPaletteAction[] {
togglePseudoLocale();
},
});
// eslint-enable @grafana/no-untranslated-strings
// eslint-enable @grafana/i18n/no-untranslated-strings
}
return actions;

@ -76,7 +76,7 @@ export const ConfigureCorrelationSourceForm = () => {
<span className={styles.variable} key={i}>
{name}
{i < variables.length - 1
? // eslint-disable-next-line @grafana/no-untranslated-strings
? // eslint-disable-next-line @grafana/i18n/no-untranslated-strings
', '
: ''}
</span>

@ -138,7 +138,7 @@ const TransformationEditorRow = (props: Props) => {
<Label htmlFor={`config.transformations.${defaultValue.id}.expression`}>
<Trans i18nKey="correlations.transform-row.expression-label">Expression</Trans>
{getSupportedTransTypeDetails(watch(`config.transformations.${index}.type`)).expressionDetails.required
? // eslint-disable-next-line @grafana/no-untranslated-strings
? // eslint-disable-next-line @grafana/i18n/no-untranslated-strings
' *'
: ''}
</Label>

@ -24,7 +24,7 @@ export function EmbeddedDashboardTestPage() {
layout={PageLayoutType.Canvas}
>
{/* this is a test page, no need to translate */}
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Box paddingY={2}>Internal url state: {state}</Box>
<EmbeddedDashboard uid="lVE-2YFMz" initialState={state} onStateChange={setState} />
</Page>

@ -80,7 +80,6 @@ function VariableList({ set }: { set: SceneVariableSet }) {
// TODO fix keyboard a11y here
// eslint-disable-next-line jsx-a11y/no-static-element-interactions,jsx-a11y/click-events-have-key-events
<div className={styles.variableItem} key={variable.state.name} onClick={() => onEditVariable(variable)}>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
<Text>${variable.state.name}</Text>
<Stack direction="row" gap={1} alignItems="center">
<Button variant="primary" size="sm" fill="outline">

@ -48,7 +48,7 @@ export function CustomVariableForm({
<VariableTextAreaField
name="Values separated by comma"
defaultValue={query}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="1, 10, mykey : myvalue, myvalue, escaped\,value"
onBlur={onQueryChange}
required

@ -60,7 +60,7 @@ export function DataSourceVariableForm({
<VariableTextField
defaultValue={regex}
name="Instance name filter"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="/.*-(.*)-.*/"
onBlur={onRegExBlur}
description={

@ -52,7 +52,7 @@ export function IntervalVariableForm({
<VariableTextField
defaultValue={intervals}
name="Values"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="1m,10m,1h,6h,1d,7d"
onBlur={onIntervalsChange}
testId={selectors.pages.Dashboard.Settings.Variables.Edit.IntervalVariable.intervalsValueInput}
@ -91,7 +91,7 @@ export function IntervalVariableForm({
'dashboard-scene.interval-variable-form.description-calculated-value-below-threshold',
'The calculated value will not go below this threshold'
)}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="10s"
onChange={onAutoMinIntervalChanged}
width={11}

@ -125,7 +125,7 @@ export function QueryVariableEditorForm({
</Trans>
</div>
}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="/.*-(?<text>.*)-(?<value>.*)-.*/"
onBlur={onRegExChange}
testId={selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRegExInputV2}

@ -246,7 +246,7 @@ export function Editor({ variable }: { variable: QueryVariable }) {
</Trans>
</div>
}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="/.*-(?<text>.*)-(?<value>.*)-.*/"
onBlur={onRegExChange}
testId={selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRegExInputV2}

@ -106,7 +106,7 @@ export class TimePickerSettings extends PureComponent<Props, State> {
<Input
id="now-delay-input"
invalid={!this.state.isNowDelayValid}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="0m"
onChange={this.onNowDelayChange}
defaultValue={this.props.nowDelay}

@ -190,7 +190,7 @@ export const EmailSharingConfiguration = ({ dashboard }: { dashboard: DashboardM
<div className={styles.emailContainer}>
<Input
className={styles.emailInput}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="me@example.com"
autoCapitalize="none"
{...register('email', {

@ -217,7 +217,7 @@ export const TransformationOperationRow = ({
<QueryOperationRow
id={id}
index={index}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
title={`${index + 1} - ${uiConfig.name}`}
draggable
actions={renderActions}

@ -128,7 +128,7 @@ export const ResourceDimensionEditor = (
labelWidth={labelWidth}
grow={true}
>
{/* eslint-disable-next-line @grafana/no-untranslated-strings*/}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings*/}
<div>TODO mappings editor!</div>
</InlineField>
</InlineFieldRow>

@ -191,10 +191,7 @@ export class ThresholdsEditor extends PureComponent<Props, State> {
enableNamedColors={true}
/>
</div>
{isPercent && (
// eslint-disable-next-line @grafana/no-untranslated-strings
<div className={styles.percentIcon}>%</div>
)}
{isPercent && <div className={styles.percentIcon}>%</div>}
</div>
}
suffix={

@ -123,7 +123,7 @@ export function ValueMappingEditRow({ mapping, index, onChange, onRemove, onDupl
const specialMatchOptions: Array<SelectableValue<SpecialValueMatch>> = [
{
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label: 'Null',
value: SpecialValueMatch.Null,
description: t(
@ -132,7 +132,7 @@ export function ValueMappingEditRow({ mapping, index, onChange, onRemove, onDupl
),
},
{
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label: 'NaN',
value: SpecialValueMatch.NaN,
description: t(
@ -141,7 +141,7 @@ export function ValueMappingEditRow({ mapping, index, onChange, onRemove, onDupl
),
},
{
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label: 'Null + NaN',
value: SpecialValueMatch.NullAndNaN,
description: t(
@ -150,7 +150,7 @@ export function ValueMappingEditRow({ mapping, index, onChange, onRemove, onDupl
),
},
{
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label: 'True',
value: SpecialValueMatch.True,
description: t(
@ -159,7 +159,7 @@ export function ValueMappingEditRow({ mapping, index, onChange, onRemove, onDupl
),
},
{
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label: 'False',
value: SpecialValueMatch.False,
description: t(

@ -108,7 +108,7 @@ export function ExploreRunQueryButton({
runQuery(pane[0]);
onClick?.();
}}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label={`${paneLabel}: ${buttonText.translation}`}
disabled={isInvalid || pane[0] === undefined}
/>

@ -78,11 +78,11 @@ export const LogsMetaRow = memo(
const downloadMenu = (
<Menu>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Menu.Item label="txt" onClick={() => download(DownloadFormat.Text)} />
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Menu.Item label="json" onClick={() => download(DownloadFormat.Json)} />
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Menu.Item label="csv" onClick={() => download(DownloadFormat.CSV)} />
</Menu>
);

@ -216,7 +216,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
ariaLabel="Select min span duration"
onChange={(val) => setSpanFiltersSearch({ ...search, from: val })}
isInvalidError="Invalid duration"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="e.g. 100ms, 1.2s"
width={18}
value={search.from || ''}
@ -233,7 +233,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
ariaLabel="Select max span duration"
onChange={(val) => setSpanFiltersSearch({ ...search, to: val })}
isInvalidError="Invalid duration"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="e.g. 100ms, 1.2s"
width={18}
value={search.to || ''}

@ -157,7 +157,7 @@ export const TracePageHeader = memo((props: TracePageHeaderProps) => {
)}
{method && method.length > 0 && (
<Tooltip
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
content="http.method"
interactive={true}
>
@ -168,7 +168,7 @@ export const TracePageHeader = memo((props: TracePageHeaderProps) => {
)}
{status && status.length > 0 && (
<Tooltip
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
content="http.status_code"
interactive={true}
>

@ -108,7 +108,11 @@ export default function AccordianLogs({
return (
<div className={styles.AccordianLogs}>
<HeaderComponent className={styles.AccordianLogsHeader} {...headerProps}>
{arrow} <strong>Events</strong> ({logs.length})
{arrow}{' '}
<strong>
<Trans i18nKey="explore.accordian-logs.events">Events</Trans>
</strong>{' '}
({logs.length})
</HeaderComponent>
{isOpen && (
<div className={styles.AccordianLogsContent}>

@ -17,7 +17,7 @@ export function getExploreExtensionConfigs(): PluginExtensionAddedLinkConfig[] {
return [
createAddedLinkConfig<PluginExtensionExploreContext>({
// This is called at the top level, so will break if we add a translation here 😱
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
title: 'Add to dashboard',
description: 'Use the query and panel from explore and create/add it to a dashboard',
targets: [PluginExtensionPoints.ExploreToolbarAction],
@ -44,9 +44,9 @@ export function getExploreExtensionConfigs(): PluginExtensionAddedLinkConfig[] {
}),
createAddedLinkConfig<PluginExtensionExploreContext>({
// This is called at the top level, so will break if we add a translation here 😱
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
title: 'Add correlation',
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
description: 'Create a correlation from this query',
targets: [PluginExtensionPoints.ExploreToolbarAction],
icon: 'link',

@ -106,7 +106,7 @@ export const SignupInvitedPage = () => {
label={t('invites.signup-invited-page.label-email', 'Email')}
>
<Input
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="email@example.com"
{...register('email', {
required: 'Email is required',

@ -165,7 +165,7 @@ class UnthemedDashboardImport extends PureComponent<Props> {
const styles = importStyles(this.props.theme);
const GcomDashboardsLink = () => (
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
<TextLink variant="bodySmall" href="https://grafana.com/grafana/dashboards/" external>
grafana.com/dashboards
</TextLink>

@ -17,7 +17,7 @@ export function AlertWithTraceID(props: AlertWithTraceIDProps) {
{traceID && (
/* Deliberately don't want to translate 'Trace ID' */
/* eslint-disable-next-line @grafana/no-untranslated-strings */
/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */
<Text element="p" color="secondary" variant="bodySmall">
Trace ID: {traceID}
</Text>

@ -79,7 +79,7 @@ export const UserInviteForm = () => {
error={!!errors.loginOrEmail ? 'Email or username is required' : undefined}
label={t('org.user-invite-form.label-email-or-username', 'Email or username')}
>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Input {...register('loginOrEmail', { required: true })} placeholder="email@example.com" />
</Field>
<Field invalid={!!errors.name} label={t('org.user-invite-form.label-name', 'Name')}>

@ -246,7 +246,7 @@ export function PluginDetailsPanel(props: Props): React.ReactElement | null {
This feature is for reporting malicious or harmful behaviour within plugins. For plugin concerns, email
us at:{' '}
</Trans>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<TextLink href="mailto:integrations+report-plugin@grafana.com">integrations@grafana.com</TextLink>
</Text>
<Text>

@ -13,9 +13,9 @@ PluginPageContext.displayName = 'PluginPageContext';
function getInitialPluginPageContext(): PluginPageContextType {
return {
sectionNav: {
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
main: { text: 'Plugin page' },
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
node: { text: 'Plugin page' },
},
};

@ -377,7 +377,7 @@ export function createExtensionSubMenu(extensions: PluginExtensionLink[]): Panel
if (uncategorized.length > 0) {
if (subMenu.length > 0) {
subMenu.push({
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
text: 'divider',
type: 'divider',
});

@ -10,7 +10,7 @@ export function TokenPermissionsInfo() {
return (
<div className={styles.container}>
{/* GitHub UI is English only, so these strings are not translated */}
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable @grafana/i18n/no-untranslated-strings */}
<Stack gap={0.5} wrap={'wrap'}>
<Trans i18nKey="provisioning.token-permissions-info.go-to">Go to</Trans>
<TextLink external href="https://github.com/settings/personal-access-tokens/new">
@ -20,21 +20,22 @@ export function TokenPermissionsInfo() {
<strong>"Fine-grained token".</strong>
<Trans i18nKey="provisioning.token-permissions-info.make-sure">Make sure to include these permissions</Trans>:
</Stack>
{/* eslint-enable @grafana/i18n/no-untranslated-strings */}
<ul className={styles.permissionsList}>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<li>
Content: <span className={styles.accessLevel}>Read and write</span>
</li>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<li>
Metadata: <span className={styles.accessLevel}>Read only</span>
</li>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<li>
Pull requests: <span className={styles.accessLevel}>Read and write</span>
</li>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<li>
Webhooks: <span className={styles.accessLevel}>Read and write</span>
</li>

@ -237,7 +237,6 @@ export function ProvisioningWizard({ type }: { type: RepoType }) {
<FormPrompt onDiscard={handleCancel} confirmRedirect={isDirty && activeStep !== 'finish' && !isCancelling} />
<Stack direction="column">
<Box marginBottom={2}>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
<Text element="h2">
{currentStepIndex + 1}. {currentStepConfig?.title}
</Text>

@ -138,7 +138,6 @@ const renderDataSource = <TQuery extends DataQuery>(
const { alerting, dataSource, onChangeDataSource } = props;
if (!onChangeDataSource) {
// eslint-disable-next-line @grafana/no-untranslated-strings
return <em className={styles.contextInfo}>({dataSource.name})</em>;
}

@ -169,7 +169,7 @@ export const QueryGroupOptionsEditor = React.memo(({ options, dataSource, data,
<Input
id="cache-timeout-id"
type="text"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="60"
spellCheck={false}
onBlur={onCacheTimeoutBlur}
@ -193,7 +193,7 @@ export const QueryGroupOptionsEditor = React.memo(({ options, dataSource, data,
</InlineLabel>
<Input
type="number"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder={`${dataSource.cachingConfig.TTLMs}`}
spellCheck={false}
onBlur={onQueryCachingTTLBlur}
@ -226,7 +226,7 @@ export const QueryGroupOptionsEditor = React.memo(({ options, dataSource, data,
<Input
id="max-data-points-input"
type="number"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder={`${realMd}`}
spellCheck={false}
onBlur={onMaxDataPointsBlur}
@ -267,7 +267,7 @@ export const QueryGroupOptionsEditor = React.memo(({ options, dataSource, data,
<Input
id="min-interval-input"
type="text"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder={`${minIntervalOnDs}`}
spellCheck={false}
onBlur={onMinIntervalBlur}
@ -359,7 +359,7 @@ export const QueryGroupOptionsEditor = React.memo(({ options, dataSource, data,
<Input
id="relative-time-input"
type="text"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="1h"
onChange={onRelativeTimeChange}
onBlur={onOverrideTime}
@ -385,7 +385,7 @@ export const QueryGroupOptionsEditor = React.memo(({ options, dataSource, data,
<Input
id="time-shift-input"
type="text"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="1h"
onChange={onTimeShiftChange}
onBlur={onTimeShift}

@ -1,4 +1,4 @@
/* eslint-disable @grafana/no-untranslated-strings */
/* eslint-disable @grafana/i18n/no-untranslated-strings */
import { NavModelItem } from '@grafana/data';
import { usePluginLinks } from '@grafana/runtime';
import { Button, LinkButton, Stack, Text } from '@grafana/ui';

@ -81,7 +81,7 @@ export const CreateTeam = (): JSX.Element => {
'This is optional and is primarily used for allowing custom team avatars'
)}
>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Input {...register('email')} type="email" id="team-email" placeholder="email@test.com" />
</Field>
</FieldSet>

@ -78,7 +78,7 @@ export const TeamSettings = ({ team, updateTeam }: Props) => {
)}
disabled={!canWriteTeamSettings}
>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
<Input {...register('email')} placeholder="team@email.com" type="email" id="email-input" />
</Field>
<Button type="submit" disabled={!canWriteTeamSettings}>

@ -59,11 +59,7 @@ export const UnaryOperationEditor = (props: {
>
<Select options={ops} value={unary?.operator ?? ops[0].value} onChange={onUnaryOperationChanged} />
</InlineField>
<InlineField
// eslint-disable-next-line @grafana/no-untranslated-strings
label="("
labelWidth={2}
>
<InlineField label="(" labelWidth={2}>
<Select
placeholder={t('transformers.unary-operation-editor.placeholder-field', 'Field')}
className="min-width-11"
@ -72,7 +68,6 @@ export const UnaryOperationEditor = (props: {
onChange={onUnaryValueChanged}
/>
</InlineField>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
<InlineLabel width={2}>)</InlineLabel>
</InlineFieldRow>
</>

@ -174,7 +174,7 @@ export const ConvertFieldTypeTransformerEditor = ({
>
<Input
value={c.dateFormat}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder={'e.g. YYYY-MM-DD'}
onChange={onInputFormat(idx)}
width={24}
@ -193,7 +193,7 @@ export const ConvertFieldTypeTransformerEditor = ({
>
<Input
value={c.joinWith}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder={'JSON'}
onChange={onJoinWithChange(idx)}
width={16}
@ -211,7 +211,7 @@ export const ConvertFieldTypeTransformerEditor = ({
>
<Input
value={c.dateFormat}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder={'e.g. YYYY-MM-DD'}
onChange={onInputFormat(idx)}
width={24}

@ -81,7 +81,7 @@ export function FormatTimeTransfomerEditor({
value={options.timeField}
onChange={onSelectField}
/* don't translate here as this references a field name */
/* eslint-disable-next-line @grafana/no-untranslated-strings */
/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */
placeholder="time"
isClearable
/>

@ -90,7 +90,7 @@ export function SeriesToFieldsTransformerEditor({ input, options, onChange }: Tr
value={options.byField}
onChange={onSelectField}
/* don't translate here as this references a field name */
/* eslint-disable-next-line @grafana/no-untranslated-strings */
/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */
placeholder="time"
isClearable
/>

@ -118,7 +118,7 @@ export const extractFieldsTransformerEditor = ({
{options.format === FieldExtractorID.RegExp && (
<InlineFieldRow>
<InlineField
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
label="RegExp"
labelWidth={16}
interactive={true}
@ -127,7 +127,7 @@ export const extractFieldsTransformerEditor = ({
})}
>
<Input
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="/(?<NewField>.*)/"
value={options.regExp}
onChange={onRegexpChange}

@ -147,7 +147,6 @@ export function JoinByLabelsTransformerEditor({ input, options, onChange }: Prop
{Boolean(info.addOptions.length && idx === options.join!.length - 1) && (
<ValuePicker
icon="plus"
// eslint-disable-next-line @grafana/no-untranslated-strings
label={''}
options={info.addOptions}
onChange={addJoin}

@ -37,7 +37,7 @@ export const intervalVariableSlice = createSlice({
// add auto option if missing
if (options.length && options[0].text !== 'auto') {
options.unshift({
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
text: 'auto',
value: '$__auto_interval_' + instanceState.name,
selected: false,

@ -87,7 +87,6 @@ export const generateLabel = (feature: FeatureLike, idx: number): string | React
if (first) {
return (
// eslint-disable-next-line @grafana/no-untranslated-strings
<span>
{first}: {renderValue(props[first])}
</span>
@ -98,7 +97,6 @@ export const generateLabel = (feature: FeatureLike, idx: number): string | React
const v = props[k];
if (isString(v)) {
return (
// eslint-disable-next-line @grafana/no-untranslated-strings
<span>
{k}: {renderValue(v)}
</span>

@ -88,7 +88,7 @@ export const AppRegistrationCredentials = (props: AppRegistrationCredentialsProp
<Input
aria-label={t('components.app-registration-credentials.aria-label-tenant-id', 'Tenant ID')}
className="width-30"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.tenantId || ''}
onChange={onTenantIdChange}
@ -106,7 +106,7 @@ export const AppRegistrationCredentials = (props: AppRegistrationCredentialsProp
<Input
className="width-30"
aria-label={t('components.app-registration-credentials.aria-label-client-id', 'Client ID')}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.clientId || ''}
onChange={onClientIdChange}
@ -150,7 +150,7 @@ export const AppRegistrationCredentials = (props: AppRegistrationCredentialsProp
<Input
className="width-30"
aria-label={t('components.app-registration-credentials.aria-label-client-secret', 'Client Secret')}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.clientSecret || ''}
onChange={onClientSecretChange}

@ -154,7 +154,7 @@ export class ConfigEditor extends PureComponent<Props, State> {
value={options.jsonData.timeout}
type="number"
className="width-15"
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="30"
onChange={onTimeoutChange}
/>

@ -74,7 +74,7 @@ const AdvancedResourcePicker = ({ resources, onChange }: ResourcePickerProps<str
id={`input-advanced-resource-picker-${index + 1}`}
value={resource}
onChange={(event) => onResourceChange(index, event.currentTarget.value)}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="ex: /subscriptions/$subId"
data-testid={`input-advanced-resource-picker-${index + 1}`}
/>

@ -73,7 +73,7 @@ const AdvancedResourcePicker = ({ resources, onChange }: ResourcePickerProps<Azu
id={`input-advanced-resource-picker-subscription`}
value={resources[0]?.subscription ?? ''}
onChange={(event) => onCommonPropChange({ subscription: event.currentTarget.value })}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"
/>
</InlineField>
@ -91,7 +91,7 @@ const AdvancedResourcePicker = ({ resources, onChange }: ResourcePickerProps<Azu
id={`input-advanced-resource-picker-metricNamespace`}
value={resources[0]?.metricNamespace ?? ''}
onChange={(event) => onCommonPropChange({ metricNamespace: event.currentTarget.value })}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="Microsoft.Insights/metricNamespaces"
/>
</InlineField>
@ -111,7 +111,7 @@ const AdvancedResourcePicker = ({ resources, onChange }: ResourcePickerProps<Azu
id={`input-advanced-resource-picker-region`}
value={resources[0]?.region ?? ''}
onChange={(event) => onCommonPropChange({ region: event.currentTarget.value })}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="northeurope"
/>
</InlineField>
@ -142,7 +142,7 @@ const AdvancedResourcePicker = ({ resources, onChange }: ResourcePickerProps<Azu
onChange={(event) =>
onResourceChange(index, { ...resource, resourceGroup: event.currentTarget.value })
}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="resource-group"
/>
<AccessoryButton

@ -56,7 +56,7 @@ export function CheatSheet() {
</li>
</ul>
<Trans i18nKey="cheat-sheet.macros">Macros:</Trans>
{/* eslint-disable @grafana/no-untranslated-strings */}
{/* eslint-disable @grafana/i18n/no-untranslated-strings */}
<ul className={styles.ulPadding}>
<li>$__time(column) -&gt; column AS time</li>
<li>$__timeEpoch(column) -&gt; DATEDIFF(second, &apos;1970-01-01&apos;, column) AS time</li>
@ -84,13 +84,13 @@ export function CheatSheet() {
<li>$__unixEpochGroup(column,&apos;5m&apos;) -&gt; FLOOR(column/300)*300</li>
<li>$__unixEpochGroupAlias(column,&apos;5m&apos;) -&gt; FLOOR(column/300)*300 AS [time]</li>
</ul>
{/* eslint-enable @grafana/no-untranslated-strings */}
{/* eslint-enable @grafana/i18n/no-untranslated-strings */}
<p>
<Trans i18nKey="cheat-sheet.example-time-group" values={{ timeGroupMacro: '$__timeGroup' }}>
Example of group by and order by with {'{{timeGroupMacro}}'}:
</Trans>
</p>
{/* eslint-disable @grafana/no-untranslated-strings */}
{/* eslint-disable @grafana/i18n/no-untranslated-strings */}
<pre>
<code>
SELECT $__timeGroup(date_time_col, &apos;1h&apos;) AS time, sum(value) as value <br />
@ -102,11 +102,11 @@ export function CheatSheet() {
<br />
</code>
</pre>
{/* eslint-enable @grafana/no-untranslated-strings */}
{/* eslint-enable @grafana/i18n/no-untranslated-strings */}
<Trans i18nKey="cheat-sheet.condtional-macros">
Or build your own conditionals using these macros which just return the values:
</Trans>
{/* eslint-disable @grafana/no-untranslated-strings */}
{/* eslint-disable @grafana/i18n/no-untranslated-strings */}
<ul className={styles.ulPadding}>
<li>$__timeFrom() -&gt; &apos;2017-04-21T05:01:17Z&apos;</li>
<li>$__timeTo() -&gt; &apos;2017-04-21T05:01:17Z&apos;</li>
@ -115,7 +115,7 @@ export function CheatSheet() {
<li>$__unixEpochNanoFrom() -&gt; 1494410783152415214</li>
<li>$__unixEpochNanoTo() -&gt; 1494497183142514872</li>
</ul>
{/* eslint-enable @grafana/no-untranslated-strings */}
{/* eslint-enable @grafana/i18n/no-untranslated-strings */}
</div>
);
}

@ -180,7 +180,7 @@ export const AzureCredentialsForm = (props: Props) => {
>
<Input
width={45}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.tenantId || ''}
onChange={onTenantIdChange}
@ -197,7 +197,7 @@ export const AzureCredentialsForm = (props: Props) => {
>
<Input
width={45}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.clientId || ''}
onChange={onClientIdChange}
@ -242,7 +242,7 @@ export const AzureCredentialsForm = (props: Props) => {
<Input
width={45}
aria-label={t('azureauth.azure-credentials-form.aria-label-client-secret', 'Client Secret')}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.clientSecret || ''}
onChange={onClientSecretChange}

@ -162,7 +162,7 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
name="host"
type="text"
value={dsSettings.url || ''}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="localhost:1433"
onChange={onDSOptionChanged('url')}
/>
@ -367,7 +367,7 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
value={dsSettings.user || ''}
placeholder={
jsonData.authenticationType === MSSQLAuthenticationType.kerberosRaw
? // eslint-disable-next-line @grafana/no-untranslated-strings
? // eslint-disable-next-line @grafana/i18n/no-untranslated-strings
'name@EXAMPLE.COM'
: t('configuration.configuration-editor.placeholder-user', 'user')
}
@ -434,7 +434,7 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
>
<Input
width={LONG_WIDTH}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="1m"
value={jsonData.timeInterval || ''}
onChange={onUpdateDatasourceJsonDataOption(props, 'timeInterval')}

@ -62,7 +62,7 @@ export const KerberosConfig = (props: DataSourcePluginOptionsEditorProps<MssqlOp
error={'Keytab file path is required'}
>
<Input
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="/home/grot/grot.keytab"
onChange={onKeytabFileChanged}
width={LONG_WIDTH}
@ -85,7 +85,7 @@ export const KerberosConfig = (props: DataSourcePluginOptionsEditorProps<MssqlOp
)}
>
<Input
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="/tmp/krb5cc_1000"
onChange={onCredentialCacheChanged}
width={LONG_WIDTH}
@ -124,7 +124,7 @@ export const KerberosConfig = (props: DataSourcePluginOptionsEditorProps<MssqlOp
)}
>
<Input
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="/home/grot/cache.json"
onChange={onCredentialCacheFileChanged}
width={LONG_WIDTH}
@ -179,7 +179,7 @@ export const KerberosAdvancedSettings = (props: DataSourcePluginOptionsEditorPro
<Input
type="text"
width={LONG_WIDTH}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="0"
defaultValue={jsonData.UDPConnectionLimit}
onChange={(e) => {
@ -207,7 +207,7 @@ export const KerberosAdvancedSettings = (props: DataSourcePluginOptionsEditorPro
<Input
type="text"
width={LONG_WIDTH}
// eslint-disable-next-line @grafana/no-untranslated-strings
// eslint-disable-next-line @grafana/i18n/no-untranslated-strings
placeholder="true"
defaultValue={jsonData.enableDNSLookupKDC}
onChange={onDNSLookupKDCChanged}

@ -5798,6 +5798,7 @@
},
"explore": {
"accordian-logs": {
"events": "Events",
"footer": "Event timestamps are relative to the start time of the full trace."
},
"accordian-references": {

@ -127,8 +127,6 @@ export const Page = () => {
persistAuthorization={false}
/>
)}
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
{!url?.value && <div>...{/** TODO, we can make an api docs loading page here */}</div>}
</NamespaceContext.Provider>
</ThemeProvider>

Loading…
Cancel
Save