diff --git a/.changeset/modern-apricots-flash.md b/.changeset/modern-apricots-flash.md
new file mode 100644
index 00000000..1901cb47
--- /dev/null
+++ b/.changeset/modern-apricots-flash.md
@@ -0,0 +1,5 @@
+---
+'@intlify/eslint-plugin-vue-i18n': minor
+---
+
+add lowercase option to key-format-style rule
diff --git a/docs/rules/key-format-style.md b/docs/rules/key-format-style.md
index f038388b..38eb8f52 100644
--- a/docs/rules/key-format-style.md
+++ b/docs/rules/key-format-style.md
@@ -13,6 +13,7 @@ This rule aims to enforces specific casing for localization key names.
```yaml
camelCaseKey: The key for this value is camel case.
kebab-case-key: The key for this value is kebab case.
+lowercase: The key for this value is lower case.
snake_case_key: The key for this value is snake case.
mixed_Case-key: Perhaps you don't want to use this casing.
```
@@ -47,7 +48,7 @@ Also, the following localization key definitions are reported as errors, because
{
"@intlify/vue-i18n/key-format-style": [
"error",
- "camelCase" | "kebab-case" | "snake_case",
+ "camelCase" | "kebab-case" | "lowercase" | "snake_case",
{
"allowArray": false,
"splitByDots": false
@@ -112,6 +113,32 @@ appTitle: I18N Management System
app_title: I18N Management System
```
+:+1: Examples of **correct** code for this rule with `"lowercase"`:
+
+
+
+```yaml
+# eslint @intlify/vue-i18n/key-format-style: ['error', 'lowercase']
+
+# ✓ GOOD
+apptitle: I18N Management System
+```
+
+
+
+:-1: Examples of **incorrect** code for this rule with `"lowercase"`:
+
+
+
+```yaml
+# eslint @intlify/vue-i18n/key-format-style: ['error', 'lowercase']
+
+# ✗ BAD
+appTitle: I18N Management System
+app_title: I18N Management System
+APP_TITLE: I18N Management System
+```
+
:+1: Examples of **correct** code for this rule with `"snake_case"`:
diff --git a/lib/rules/key-format-style.ts b/lib/rules/key-format-style.ts
index 1842a590..30da1611 100644
--- a/lib/rules/key-format-style.ts
+++ b/lib/rules/key-format-style.ts
@@ -16,6 +16,7 @@ const debug = debugBuilder('eslint-plugin-vue-i18n:key-format-style')
const allowedCaseOptions = [
'camelCase',
'kebab-case',
+ 'lowercase',
'snake_case',
'SCREAMING_SNAKE_CASE'
] as const
diff --git a/lib/utils/casing.ts b/lib/utils/casing.ts
index 1c983385..1ee99d7b 100644
--- a/lib/utils/casing.ts
+++ b/lib/utils/casing.ts
@@ -75,6 +75,20 @@ export function isCamelCase(str: string): boolean {
return true
}
+/**
+ * Checks whether the given string is lowercase.
+ */
+export function isLowerCase(str: string): boolean {
+ if (
+ hasSymbols(str) ||
+ hasUpper(str) ||
+ /-|_|\s/u.exec(str) // kebab or snake or space
+ ) {
+ return false
+ }
+ return true
+}
+
/**
* Checks whether the given string is PascalCase.
*/
@@ -104,6 +118,7 @@ const checkersMap = {
'kebab-case': isKebabCase,
snake_case: isSnakeCase,
camelCase: isCamelCase,
+ lowercase: isLowerCase,
PascalCase: isPascalCase,
SCREAMING_SNAKE_CASE: isScreamingSnakeCase
}
@@ -127,6 +142,7 @@ export function pascalCase(str: string): string {
export const allowedCaseOptions = [
'camelCase',
'kebab-case',
+ 'lowercase',
'PascalCase',
'snake_case',
'SCREAMING_SNAKE_CASE'
diff --git a/tests/lib/rules/key-format-style.ts b/tests/lib/rules/key-format-style.ts
index 71ac624b..9f758413 100644
--- a/tests/lib/rules/key-format-style.ts
+++ b/tests/lib/rules/key-format-style.ts
@@ -129,6 +129,41 @@ tester.run('key-format-style', rule as never, {
...options.json.file,
options: ['kebab-case']
},
+ {
+ code: `
+ lowercase:
+ foobar: kebab-value
+ `,
+ ...options.yaml.file
+ },
+ {
+ code: `{
+ "lowercase": {
+ "foobar": "kebab-value"
+ }
+ }
+ `,
+ ...options.json.file
+ },
+ {
+ code: `
+ en-US:
+ lowercase:
+ foobar: kebab-value
+ `,
+ ...options.yaml.key
+ },
+ {
+ code: `{
+ "en-US": {
+ "lowercase": {
+ "foobar": "kebab-value"
+ }
+ }
+ }
+ `,
+ ...options.json.key
+ },
{
code: `
snake_case:
@@ -379,6 +414,136 @@ tester.run('key-format-style', rule as never, {
}
]
},
+ {
+ code: `
+ foo-bar: baz
+ `,
+ ...options.yaml.file,
+ options: ['lowercase'],
+ errors: [
+ {
+ message: '"foo-bar" is not lowercase',
+ line: 2
+ }
+ ]
+ },
+ {
+ code: `
+ en-US:
+ foo-bar: baz
+ `,
+ ...options.yaml.key,
+ options: ['lowercase'],
+ errors: [
+ {
+ message: '"foo-bar" is not lowercase',
+ line: 3
+ }
+ ]
+ },
+ {
+ code: `
+ {"foo-bar": "baz"}
+ `,
+ ...options.json.file,
+ options: ['lowercase'],
+ errors: [
+ {
+ message: '"foo-bar" is not lowercase',
+ line: 2
+ }
+ ]
+ },
+ {
+ code: `
+ {"en-US": {
+ "foo-bar": "baz"
+ }}`,
+ ...options.json.key,
+ options: ['lowercase'],
+ errors: [
+ {
+ message: '"foo-bar" is not lowercase',
+ line: 3
+ }
+ ]
+ },
+ {
+ code: `
+ kebab-case:
+ snake_case: camelCase
+ `,
+ ...options.yaml.file,
+ options: ['lowercase'],
+ errors: [
+ {
+ message: '"kebab-case" is not lowercase',
+ line: 2
+ },
+ {
+ message: '"snake_case" is not lowercase',
+ line: 3
+ }
+ ]
+ },
+ {
+ code: `{
+ "kebab-case": {
+ "snake_case": "camelCase"
+ }
+ }
+ `,
+ ...options.json.file,
+ options: ['lowercase'],
+ errors: [
+ {
+ message: '"kebab-case" is not lowercase',
+ line: 2
+ },
+ {
+ message: '"snake_case" is not lowercase',
+ line: 3
+ }
+ ]
+ },
+ {
+ code: `
+ SCREAMING_SNAKE_CASE:
+ PascalCase: camelCase
+ `,
+ ...options.yaml.file,
+ options: ['lowercase'],
+ errors: [
+ {
+ message: '"SCREAMING_SNAKE_CASE" is not lowercase',
+ line: 2
+ },
+ {
+ message: '"PascalCase" is not lowercase',
+ line: 3
+ }
+ ]
+ },
+ {
+ code: `{
+ "SCREAMING_SNAKE_CASE": {
+ "PascalCase": "camelCase"
+ }
+ }
+ `,
+ ...options.json.file,
+ options: ['lowercase'],
+ errors: [
+ {
+ message: '"SCREAMING_SNAKE_CASE" is not lowercase',
+ line: 2
+ },
+ {
+ message: '"PascalCase" is not lowercase',
+ line: 3
+ }
+ ]
+ },
{
code: `
- foo