{"id":49354976,"url":"https://github.com/logseq/logseq-i18n-lint","last_synced_at":"2026-04-27T13:01:34.967Z","repository":{"id":351934374,"uuid":"1211055353","full_name":"logseq/logseq-i18n-lint","owner":"logseq","description":"AST-based i18n linting for Clojure/ClojureScript projects.","archived":false,"fork":false,"pushed_at":"2026-04-17T04:38:00.000Z","size":95,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-17T06:29:01.613Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/logseq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-15T02:54:14.000Z","updated_at":"2026-04-17T04:38:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/logseq/logseq-i18n-lint","commit_stats":null,"previous_names":["logseq/logseq-i18n-lint"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/logseq/logseq-i18n-lint","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logseq%2Flogseq-i18n-lint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logseq%2Flogseq-i18n-lint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logseq%2Flogseq-i18n-lint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logseq%2Flogseq-i18n-lint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/logseq","download_url":"https://codeload.github.com/logseq/logseq-i18n-lint/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logseq%2Flogseq-i18n-lint/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32337274,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-27T13:01:31.172Z","updated_at":"2026-04-27T13:01:34.940Z","avatar_url":"https://github.com/logseq.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# logseq-i18n-lint\n\nAST-level i18n checks for hardcoded UI strings, unused translation keys, and missing translation keys in Clojure/ClojureScript source code.\n\n## Overview\n\n`logseq-i18n-lint` analyzes Clojure/ClojureScript source files at the AST level to find hardcoded UI strings that should be internationalized. Unlike regex-based approaches, it understands the code structure — hiccup vectors, function calls, attribute maps — to accurately detect strings that are displayed to users.\n\n## Features\n\n- **AST-level analysis** — Custom Clojure/ClojureScript parser, not regex matching\n- **8 detection categories** — hiccup-text, hiccup-attr, alert-text, str-concat, format-string, conditional-text, fn-arg-text, let-text\n- **Unused key detection** — Find translation keys defined in dictionaries but never referenced in code\n- **Missing key detection** — Find translation keys referenced in code but absent from the dictionary\n- **Auto-fix** — Remove unused keys from all dictionary files with `--fix`\n- **DB-ident key derivation** — Automatically resolves built-in property/class keys from db-ident definitions\n- **Configurable exclusions** — Allow lists, regex patterns, ignore context functions\n- **Git integration** — Check only changed files with `--git-changed`\n- **Parallel processing** — Uses rayon for fast multi-file analysis\n- **Cross-platform** — Prebuilt binaries for Windows, macOS, Linux (x64 \u0026 ARM64)\n- **Two output formats** — Aligned table with Unicode support, or compact for CI\n\n## Installation\n\n### Download prebuilt binary\n\nDownload from [Releases](https://github.com/logseq/logseq-i18n-lint/releases/latest) for your platform.\n\n### Build from source\n\n```bash\ncargo install --git https://github.com/logseq/logseq-i18n-lint\n```\n\nOr clone and build:\n\n```bash\ngit clone https://github.com/logseq/logseq-i18n-lint\ncd logseq-i18n-lint\ncargo build --release\n```\n\n## Quick Start\n\n```bash\n# Run lint on the project root\nlogseq-i18n-lint lint\n\n# Use a custom config\nlogseq-i18n-lint -c .i18n-lint.toml lint\n\n# Check only git-changed files\nlogseq-i18n-lint lint --git-changed\n\n# Compact output for CI\nlogseq-i18n-lint lint -f compact\n\n# Warn only (exit 0 even if issues found)\nlogseq-i18n-lint lint --warn-only\n\n# Check for unused translation keys\nlogseq-i18n-lint check-keys\n\n# Remove unused keys from all dictionaries\nlogseq-i18n-lint check-keys --fix\n\n# Check for keys used in code but missing from the dictionary\nlogseq-i18n-lint check-missing\n```\n\n\u003e **Note:** The configuration flag `-c` is a global flag and must come **before** the subcommand:\n\u003e `logseq-i18n-lint -c .i18n-lint.toml lint`\n\n## Configuration\n\nCreate `.i18n-lint.toml` in your project root. If not present, built-in defaults are used.\n\n```toml\n# Path to the project root, relative to the directory that contains the\n# executable.  Resolution is always based on the executable location, so\n# the result is the same no matter which directory you run the binary from.\n# Leave empty when the executable is placed at the project root;\n# set to \"..\" when it lives in a subdirectory such as bin/.\nproject_root = \"\"\n\n# Shared settings used by both subcommands\ninclude_dirs    = [\"src\"]\nfile_extensions = [\"clj\", \"cljs\", \"cljc\"]\n\n# Translation functions — calls to these are never flagged\ni18n_functions = [\"t\", \"i18n/t\"]\n\n# Alert/notification functions — first keyword arg is a translation key\nalert_functions = [\"notification/show!\"]\n\n# UI component functions — keyword args are translation keys\nui_functions   = []\nui_namespaces  = []\n\n# Hiccup attribute names whose string values are flagged\nui_attributes  = [\"placeholder\", \"title\", \"aria-label\", \"alt\", \"label\"]\n\n# ── lint settings ──────────────────────────────────────────────────────────────\n[lint]\nexclude_patterns    = [\"**/test/**\", \"**/node_modules/**\"]\ntext_preview_length = 60\nallow_strings       = [\"Logseq\"]\nallow_patterns      = [\"^https?://\"]\nexception_functions = [\"throw\"]\npure_functions      = []\nformat_functions    = [\"format\", \"goog.string/format\"]\nignore_context_functions = [\n  \"js/console.log\",\n  \"log/debug\",\n  \"prn\",\n  \"re-pattern\",\n  \"ns\",\n]\n\n# ── check-keys settings ────────────────────────────────────────────────────────\n# Both `check-keys` and `check-missing` read from this section.\n# check-missing only uses: primary_dict, always_used_key_patterns, ignore_key_namespaces.\n[check-keys]\ndicts_dir                  = \"src/resources/dicts\"\nprimary_dict               = \"src/resources/dicts/en.edn\"\nalways_used_key_patterns   = [\"^:command\\\\.\"]\nignore_key_namespaces      = []\ntranslation_key_attributes = [\"i18n-key\", \"prompt-key\", \"title-key\"]\n\n# Built-in db-ident definitions (one entry per source file)\n[[check-keys.db_ident_defs]]\nfile = \"deps/db/src/logseq/db/frontend/property.cljs\"\ndef  = \"built-in-properties\"\n\n[[check-keys.db_ident_defs]]\nfile = \"deps/db/src/logseq/db/frontend/class.cljs\"\ndef  = \"built-in-classes\"\n```\n\n## CLI Reference\n\n```\nlogseq-i18n-lint [GLOBAL_OPTIONS] \u003cCOMMAND\u003e [COMMAND_OPTIONS]\n\nCommands:\n  lint           Detect hardcoded UI strings\n  check-keys     Check for unused translation keys (defined in dictionary but not used in code)\n  check-missing  Check for missing translation keys (used in code but not defined in dictionary)\n\nGlobal Options:\n  -c, --config \u003cPATH\u003e    Configuration file path [default: .i18n-lint.toml]\n  -v, --verbose          Verbose output\n  -h, --help             Print help\n  -V, --version          Print version\n\nlint Options:\n  -f, --format \u003cFORMAT\u003e  Output format: table|compact [default: table]\n  -w, --warn-only        Warn only, do not exit with error code\n  -g, --git-changed      Only check git-changed files (include_dirs and exclude_patterns still apply)\n\ncheck-keys Options:\n  --fix                  Remove unused keys from all dictionary files\n```\n\n## Detection Categories\n\n| Type | Description | Example |\n|------|-------------|---------|\n| `hiccup-text` | Direct text children of hiccup vectors | `[:div \"Hello\"]` |\n| `hiccup-attr` | UI text in hiccup attributes | `{:placeholder \"Search...\"}` |\n| `fn-arg-text` | UI function string arguments | `(ui/button \"Submit\")` |\n| `str-concat` | String concatenation in UI context | `(str \"Error: \" msg)` |\n| `conditional-text` | Text in conditionals in UI context | `(if x \"Yes\" \"No\")` |\n| `format-string` | Format strings in UI context | `(goog.string/format \"Found %d\")` |\n| `let-text` | let binding in UI context | `(let [x \"Untitled\"] [:div x])` |\n| `alert-text` | Alert/notification messages | `(notification/show! \"Done\")` |\n\n\u003e **Deep dive:** See [docs/hardcoded-string-detection.md](docs/hardcoded-string-detection.md) for how each\n\u003e rule works, automatic skip filters, known limitations, and configuration tips.\n\u003e\n\u003e For unused and missing key detection, see [docs/unused-key-detection.md](docs/unused-key-detection.md).\n\n## Output Formats\n\n### Table mode (default)\n\n```\n┌──────────────────┬─────────────────────────┬──────┬────────────────────────────┐\n│ Type             │ File                    │ Line │ Text                       │\n├──────────────────┼─────────────────────────┼──────┼────────────────────────────┤\n│ hiccup-text      │ src/frontend/editor.cljs│   48 │ \"No matched commands\"      │\n│ hiccup-attr      │ src/frontend/search.cljs│   92 │ \"Search pages...\"          │\n└──────────────────┴─────────────────────────┴──────┴────────────────────────────┘\n\nFound 2 hardcoded strings in 317 files (hiccup-text: 1, hiccup-attr: 1)\n```\n\n### Compact mode\n\n```\n[hiccup-text] src/frontend/editor.cljs:48 \"No matched commands\"\n[hiccup-attr] src/frontend/search.cljs:92 \"Search pages...\"\n\nFound 2 hardcoded strings in 317 files (hiccup-text: 1, hiccup-attr: 1)\n```\n\n## Development\n\n```bash\n# Build\ncargo build\n\n# Run tests\ncargo test\n\n# Run clippy\ncargo clippy\n\n# Run benchmarks\ncargo bench\n\n# Build release\ncargo build --release\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flogseq%2Flogseq-i18n-lint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flogseq%2Flogseq-i18n-lint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flogseq%2Flogseq-i18n-lint/lists"}