Browse Source

Merge a3c11459ca into 00427eb252

pull/1632/merge
Fedor Finenko 3 weeks ago committed by GitHub
parent
commit
21c01db5bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      .github/workflows/cd.yml
  2. 2
      .github/workflows/ci.yml
  3. 2
      .github/workflows/msrv-badge.yml
  4. 2
      .github/workflows/web-ci.yml
  5. 2
      .github/workflows/wiki.yml
  6. 1
      .gitignore
  7. 433
      Cargo.lock
  8. 10
      Cargo.toml
  9. 6
      build.rs
  10. 6
      docs/vercel/package-lock.json
  11. 4
      i18n.toml
  12. 2
      image/Cargo.toml
  13. 123
      locales/build.rs
  14. 152
      locales/en-US/cli.ftl
  15. 152
      locales/ru-RU/cli.ftl
  16. 265
      src/cli.rs
  17. 58
      src/i18n.rs
  18. 1
      src/lib.rs
  19. 10
      src/main.rs

4
.github/workflows/cd.yml

@ -15,7 +15,7 @@ jobs: @@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
@ -68,7 +68,7 @@ jobs: @@ -68,7 +68,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1

2
.github/workflows/ci.yml

@ -24,7 +24,7 @@ jobs: @@ -24,7 +24,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1

2
.github/workflows/msrv-badge.yml

@ -11,7 +11,7 @@ jobs: @@ -11,7 +11,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.ref }}
token: ${{ secrets.BADGE_TOKEN }}

2
.github/workflows/web-ci.yml

@ -19,7 +19,7 @@ jobs: @@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v5
- name: Setup Node
uses: actions/setup-node@v6

2
.github/workflows/wiki.yml

@ -16,7 +16,7 @@ jobs: @@ -16,7 +16,7 @@ jobs:
wiki:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v5
- uses: spenserblack/actions-wiki@v0.3.0
with:
path: docs/wiki

1
.gitignore vendored

@ -8,3 +8,4 @@ @@ -8,3 +8,4 @@
result
**/generated-*
**/.idea
__locales_compiled

433
Cargo.lock generated

@ -199,6 +199,15 @@ version = "0.22.1" @@ -199,6 +199,15 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "basic-toml"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "2.9.1"
@ -246,7 +255,7 @@ dependencies = [ @@ -246,7 +255,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -372,7 +381,7 @@ dependencies = [ @@ -372,7 +381,7 @@ dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"windows-link 0.1.3",
"windows-link",
]
[[package]]
@ -426,9 +435,9 @@ dependencies = [ @@ -426,9 +435,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.43"
version = "4.5.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f"
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
dependencies = [
"clap_builder",
"clap_derive",
@ -444,11 +453,23 @@ dependencies = [ @@ -444,11 +453,23 @@ dependencies = [
"clap",
]
[[package]]
name = "clap-i18n-richformatter"
version = "0.1.4"
source = "git+https://github.com/Sk7Str1p3/clap-i18n-richformatter-0.1.4#48171098e9ef30261729925e91a8d874ee3b6062"
dependencies = [
"clap",
"i18n-embed",
"i18n-embed-fl",
"rust-embed",
"unic-langid",
]
[[package]]
name = "clap_builder"
version = "4.5.43"
version = "4.5.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65"
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
dependencies = [
"anstream",
"anstyle",
@ -468,14 +489,14 @@ dependencies = [ @@ -468,14 +489,14 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.41"
version = "4.5.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -678,7 +699,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" @@ -678,7 +699,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -705,7 +726,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" @@ -705,7 +726,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -728,11 +749,11 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" @@ -728,11 +749,11 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "enable-ansi-support"
version = "0.3.1"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea7457668b3da8a4b702f3d79e131aa3e81cd7e81cc95fb2d54fce9f182ecc77"
checksum = "aa4ff3ae2a9aa54bf7ee0983e59303224de742818c1822d89f07da9856d9bc60"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.42.0",
]
[[package]]
@ -856,6 +877,15 @@ dependencies = [ @@ -856,6 +877,15 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "find-crate"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2"
dependencies = [
"toml 0.5.11",
]
[[package]]
name = "flate2"
version = "1.1.2"
@ -867,6 +897,51 @@ dependencies = [ @@ -867,6 +897,51 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "fluent"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8137a6d5a2c50d6b0ebfcb9aaa91a28154e0a70605f112d30cb0cd4a78670477"
dependencies = [
"fluent-bundle",
"unic-langid",
]
[[package]]
name = "fluent-bundle"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01203cb8918f5711e73891b347816d932046f95f54207710bda99beaeb423bf4"
dependencies = [
"fluent-langneg",
"fluent-syntax",
"intl-memoizer",
"intl_pluralrules",
"rustc-hash",
"self_cell",
"smallvec",
"unic-langid",
]
[[package]]
name = "fluent-langneg"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0"
dependencies = [
"unic-langid",
]
[[package]]
name = "fluent-syntax"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198"
dependencies = [
"memchr",
"thiserror 2.0.12",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -914,7 +989,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" @@ -914,7 +989,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -2208,6 +2283,73 @@ dependencies = [ @@ -2208,6 +2283,73 @@ dependencies = [
"libm",
]
[[package]]
name = "i18n-config"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e06b90c8a0d252e203c94344b21e35a30f3a3a85dc7db5af8f8df9f3e0c63ef"
dependencies = [
"basic-toml",
"log",
"serde",
"serde_derive",
"thiserror 1.0.69",
"unic-langid",
]
[[package]]
name = "i18n-embed"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a217bbb075dcaefb292efa78897fc0678245ca67f265d12c351e42268fcb0305"
dependencies = [
"arc-swap",
"fluent",
"fluent-langneg",
"fluent-syntax",
"i18n-embed-impl",
"intl-memoizer",
"log",
"parking_lot",
"rust-embed",
"sys-locale",
"thiserror 1.0.69",
"unic-langid",
"walkdir",
]
[[package]]
name = "i18n-embed-fl"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e598ed73b67db92f61e04672e599eef2991a262a40e1666735b8a86d2e7e9f30"
dependencies = [
"find-crate",
"fluent",
"fluent-syntax",
"i18n-config",
"i18n-embed",
"proc-macro-error2",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.110",
"unic-langid",
]
[[package]]
name = "i18n-embed-impl"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f2cc0e0523d1fe6fc2c6f66e5038624ea8091b3e7748b5e8e0c84b1698db6c2"
dependencies = [
"find-crate",
"i18n-config",
"proc-macro2",
"quote",
"syn 2.0.110",
]
[[package]]
name = "iana-time-zone"
version = "0.1.63"
@ -2415,6 +2557,25 @@ dependencies = [ @@ -2415,6 +2557,25 @@ dependencies = [
"similar",
]
[[package]]
name = "intl-memoizer"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f"
dependencies = [
"type-map",
"unic-langid",
]
[[package]]
name = "intl_pluralrules"
version = "7.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
dependencies = [
"unic-langid",
]
[[package]]
name = "inventory"
version = "0.3.20"
@ -2493,7 +2654,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" @@ -2493,7 +2654,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -2625,7 +2786,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" @@ -2625,7 +2786,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -2729,6 +2890,7 @@ dependencies = [ @@ -2729,6 +2890,7 @@ dependencies = [
"byte-unit",
"clap",
"clap-cargo",
"clap-i18n-richformatter",
"clap_complete",
"criterion",
"crossbeam-channel",
@ -2738,6 +2900,8 @@ dependencies = [ @@ -2738,6 +2900,8 @@ dependencies = [
"gix-testtools",
"globset",
"human-panic",
"i18n-embed",
"i18n-embed-fl",
"image",
"insta",
"lazy_static",
@ -2746,12 +2910,16 @@ dependencies = [ @@ -2746,12 +2910,16 @@ dependencies = [
"onefetch-image",
"onefetch-manifest",
"owo-colors",
"proc-macro2",
"quote",
"regex",
"rstest",
"rust-embed",
"serde",
"serde_json",
"serde_yaml",
"strum",
"syn 2.0.110",
"tera",
"time",
"time-humanize",
@ -2888,7 +3056,7 @@ dependencies = [ @@ -2888,7 +3056,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -3059,11 +3227,33 @@ dependencies = [ @@ -3059,11 +3227,33 @@ dependencies = [
"toml_edit",
]
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn 2.0.110",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
@ -3133,9 +3323,9 @@ dependencies = [ @@ -3133,9 +3323,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.40"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
@ -3228,7 +3418,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" @@ -3228,7 +3418,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -3351,10 +3541,44 @@ dependencies = [ @@ -3351,10 +3541,44 @@ dependencies = [
"regex",
"relative-path",
"rustc_version",
"syn 2.0.104",
"syn 2.0.110",
"unicode-ident",
]
[[package]]
name = "rust-embed"
version = "8.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "8.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn 2.0.110",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "8.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475"
dependencies = [
"sha2",
"walkdir",
]
[[package]]
name = "rust_decimal"
version = "1.37.2"
@ -3377,6 +3601,12 @@ version = "0.1.26" @@ -3377,6 +3601,12 @@ version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustc_version"
version = "0.4.1"
@ -3444,6 +3674,12 @@ version = "4.1.0" @@ -3444,6 +3674,12 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "self_cell"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33"
[[package]]
name = "semver"
version = "1.0.26"
@ -3477,7 +3713,7 @@ checksum = "87ff78ab5e8561c9a675bfc1785cb07ae721f0ee53329a595cefd8c04c2ac4e0" @@ -3477,7 +3713,7 @@ checksum = "87ff78ab5e8561c9a675bfc1785cb07ae721f0ee53329a595cefd8c04c2ac4e0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -3669,7 +3905,7 @@ dependencies = [ @@ -3669,7 +3905,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -3685,9 +3921,9 @@ dependencies = [ @@ -3685,9 +3921,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.104"
version = "2.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
dependencies = [
"proc-macro2",
"quote",
@ -3702,7 +3938,16 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" @@ -3702,7 +3938,16 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
name = "sys-locale"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
"libc",
]
[[package]]
@ -3813,7 +4058,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" @@ -3813,7 +4058,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -3824,7 +4069,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" @@ -3824,7 +4069,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -4023,6 +4268,15 @@ version = "1.0.2" @@ -4023,6 +4268,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
[[package]]
name = "type-map"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
dependencies = [
"rustc-hash",
]
[[package]]
name = "typeid"
version = "1.0.3"
@ -4056,7 +4310,7 @@ checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" @@ -4056,7 +4310,7 @@ checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -4074,6 +4328,25 @@ dependencies = [ @@ -4074,6 +4328,25 @@ dependencies = [
"arrayvec",
]
[[package]]
name = "unic-langid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05"
dependencies = [
"unic-langid-impl",
]
[[package]]
name = "unic-langid-impl"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658"
dependencies = [
"serde",
"tinystr",
]
[[package]]
name = "unicode-bom"
version = "2.0.3"
@ -4200,7 +4473,7 @@ dependencies = [ @@ -4200,7 +4473,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
"wasm-bindgen-shared",
]
@ -4222,7 +4495,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" @@ -4222,7 +4495,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -4285,7 +4558,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" @@ -4285,7 +4558,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link 0.1.3",
"windows-link",
"windows-result",
"windows-strings",
]
@ -4298,7 +4571,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" @@ -4298,7 +4571,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -4309,7 +4582,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" @@ -4309,7 +4582,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -4318,19 +4591,13 @@ version = "0.1.3" @@ -4318,19 +4591,13 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link 0.1.3",
"windows-link",
]
[[package]]
@ -4339,7 +4606,22 @@ version = "0.4.2" @@ -4339,7 +4606,22 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link 0.1.3",
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
@ -4378,15 +4660,6 @@ dependencies = [ @@ -4378,15 +4660,6 @@ dependencies = [
"windows-targets 0.53.3",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
@ -4424,7 +4697,7 @@ version = "0.53.3" @@ -4424,7 +4697,7 @@ version = "0.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
dependencies = [
"windows-link 0.1.3",
"windows-link",
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
@ -4435,6 +4708,12 @@ dependencies = [ @@ -4435,6 +4708,12 @@ dependencies = [
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
@ -4453,6 +4732,12 @@ version = "0.53.0" @@ -4453,6 +4732,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
@ -4471,6 +4756,12 @@ version = "0.53.0" @@ -4471,6 +4756,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
@ -4501,6 +4792,12 @@ version = "0.53.0" @@ -4501,6 +4792,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
@ -4519,6 +4816,12 @@ version = "0.53.0" @@ -4519,6 +4816,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
@ -4537,6 +4840,12 @@ version = "0.53.0" @@ -4537,6 +4840,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
@ -4555,6 +4864,12 @@ version = "0.53.0" @@ -4555,6 +4864,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
@ -4635,7 +4950,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" @@ -4635,7 +4950,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
"synstructure",
]
@ -4656,7 +4971,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" @@ -4656,7 +4971,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]
@ -4676,7 +4991,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" @@ -4676,7 +4991,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
"synstructure",
]
@ -4710,7 +5025,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" @@ -4710,7 +5025,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.110",
]
[[package]]

10
Cargo.toml

@ -69,6 +69,13 @@ time = { version = "0.3.41", features = ["formatting"] } @@ -69,6 +69,13 @@ time = { version = "0.3.41", features = ["formatting"] }
time-humanize = { version = "0.1.3", features = ["time"] }
tokei = "13.0.0-alpha.9"
typetag = "0.2"
i18n-embed = { version = "0.16.0", features = [
"desktop-requester",
"fluent-system",
] }
i18n-embed-fl = "0.10.0"
rust-embed = "8.9.0"
clap-i18n-richformatter = { git = "https://github.com/Sk7Str1p3/clap-i18n-richformatter-0.1.4" }
[dev-dependencies]
criterion = "0.7.0"
@ -82,9 +89,12 @@ harness = false @@ -82,9 +89,12 @@ harness = false
[build-dependencies]
lazy_static = "1"
proc-macro2 = "1.0.103"
quote = "1.0.42"
regex = "1"
serde_json = "1"
serde_yaml = "0.9"
syn = "2.0.110"
tera = { version = "1", default-features = false }
[target.'cfg(windows)'.build-dependencies]

6
build.rs

@ -7,6 +7,9 @@ use std::path::Path; @@ -7,6 +7,9 @@ use std::path::Path;
use std::sync::LazyLock;
use tera::{Context, Tera};
#[path = "locales/build.rs"]
mod locales;
fn main() -> Result<(), Box<dyn Error>> {
#[cfg(windows)]
{
@ -29,6 +32,9 @@ fn main() -> Result<(), Box<dyn Error>> { @@ -29,6 +32,9 @@ fn main() -> Result<(), Box<dyn Error>> {
)?;
fs::write(output_path, rust_code)?;
locales::concat_locales()?;
locales::generate_consts(&out_dir)?;
Ok(())
}

6
docs/vercel/package-lock.json generated

@ -2332,9 +2332,9 @@ @@ -2332,9 +2332,9 @@
"dev": true
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"license": "MIT",
"dependencies": {

4
i18n.toml

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
fallback_language = "en-US"
[fluent]
assets_dir = "__locales_compiled"

2
image/Cargo.toml

@ -15,4 +15,4 @@ image.workspace = true @@ -15,4 +15,4 @@ image.workspace = true
[target.'cfg(not(windows))'.dependencies]
color_quant = "1.1.0"
base64 = "0.22.1"
libc = "0.2.177"
libc = "0.2.174"

123
locales/build.rs

@ -0,0 +1,123 @@ @@ -0,0 +1,123 @@
use std::{
collections::BTreeMap,
fs::{create_dir_all, read_to_string, File},
io::{BufWriter, Write as _},
path::PathBuf,
};
use quote::{format_ident, quote};
/// Concatenate all FTL files in the locales directory into a single file for each locale.
pub fn concat_locales() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=locales/");
let locales_dir = PathBuf::from("locales").read_dir()?;
let out_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("__locales_compiled");
for dir in locales_dir {
let dir = dir?.path();
if !dir.is_dir() {
continue;
}
let lang = dir.components().last().unwrap();
let out_dir = out_dir.join(lang);
create_dir_all(&out_dir).unwrap();
let mut out_file = BufWriter::new(File::create(out_dir.join("onefetch.ftl"))?);
for ftl in dir.read_dir()? {
let ftl = ftl?.path();
let contents = read_to_string(&ftl)?;
writeln!(out_file, "{contents}")?;
}
}
Ok(())
}
/// Generate Rust constants for all localization keys.
// WARNING: AI slop
pub fn generate_consts(out: &String) -> Result<(), Box<dyn std::error::Error>> {
let ftl_contents = read_to_string(
PathBuf::from("__locales_compiled")
.join("en-US")
.join("onefetch.ftl"),
)?;
let out_path = PathBuf::from(out).join("locales_consts.rs");
let mut out_file = BufWriter::new(File::create(&out_path)?);
let mut keys = Vec::new();
for line in ftl_contents.lines() {
if !line.trim().contains('=') {
continue;
}
let (key, ..) = line.split_once('=').unwrap();
keys.push(key.trim().to_string());
}
// Используем struct вместо type alias
#[derive(Default)]
struct Module {
constants: Vec<(String, String)>,
submodules: BTreeMap<String, Module>,
}
let mut root = Module::default();
for key in &keys {
let parts: Vec<&str> = key.split('-').collect();
let const_name = parts.last().unwrap().to_uppercase();
let mut current = &mut root;
// Проходим по всем частям пути (кроме последней)
for part in parts.iter().take(parts.len() - 1) {
current = current
.submodules
.entry(part.to_string())
.or_insert_with(Module::default);
}
// Добавляем константу
current.constants.push((const_name, key.clone()));
}
// Рекурсивная генерация кода
fn generate_tree(module: &Module) -> proc_macro2::TokenStream {
let mut items = Vec::new();
// Добавляем константы текущего модуля
for (const_name, const_value) in &module.constants {
let const_ident = format_ident!("{}", const_name);
items.push(quote! {
pub const #const_ident: &str = #const_value;
});
}
// Добавляем подмодули
for (mod_name, submodule) in &module.submodules {
let mod_ident = format_ident!("{}", mod_name);
let submodule_code = generate_tree(submodule);
items.push(quote! {
pub mod #mod_ident {
#submodule_code
}
});
}
quote! { #(#items)* }
}
let module_code = generate_tree(&root);
let output = quote! {
pub mod locale_keys {
#module_code
}
};
writeln!(out_file, "#[rustfmt::skip]")?;
write!(out_file, "{}", output)?;
Ok(())
}

152
locales/en-US/cli.ftl

@ -0,0 +1,152 @@ @@ -0,0 +1,152 @@
cli-about = Command-line Git information tool
cli-usage-header = Usage
cli-arguments-header = Arguments
cli-arguments-input = Run as if onefetch was started in <input> instead of the current working directory
cli-options-header = Options
cli-options-help = Print help { $short ->
[true] (see more with '--help')
*[false] (see a summary with '-h')
}
cli-options-version = Print version
# Value name
cli-value-input = INPUT
cli-value-num = NUM
cli-value-field = FIELD
cli-value-regex = REGEX
cli-value-exclude = EXCLUDE
cli-value-type = TYPE
cli-value-separator = SEPARATOR
cli-value-string = STRING
cli-value-language = LANGUAGE
cli-value-when = WHEN
cli-value-image = IMAGE
cli-value-protocol = PROTOCOL
cli-value-value = VALUE
cli-value-format = FORMAT
cli-value-shell = SHELL
# INFO
cli-info-heading = INFO
cli-info-disabled_fields = Allows you to disable FIELD(s) from appearing in the output
cli-info-no_title = Hides the title
cli-info-number_of_authors-short = Maximum NUM of authors to be shown (default: {$def})
cli-info-number_of_authors-long =
Maximum NUM of authors to be shown
(default: {$def})
cli-info-number_of_languages-short = Maximum NUM of languages to be shown (default: {$def})
cli-info-number_of_languages-long =
Maximum NUM of languages to be shown
(default: {$def})
cli-info-number_of_file_churns-short = Maximum NUM of file churns to be shown (default: {$def})
cli-info-number_of_file_churns-long =
Maximum NUM of file churns to be shown
(default: {$def})
cli-info-churn_pool_size-short = Minimum NUM of commits from HEAD used to compute the churn summary
cli-info-churn_pool_size-long =
Minimum NUM of commits from HEAD used to compute the churn summary
By default, the actual value is non-deterministic due to time-based computation
and will be displayed under the info title "Churn (NUM)"
cli-info-exclude = Ignore all files & directories matching EXCLUDE
cli-info-no_bots = Exclude [bot] commits. Use <REGEX> to override the default pattern
cli-info-no_merges = Ignores merge commits
cli-info-email = Show the email address of each author
cli-info-http_url = Display repository URL as HTTP
cli-info-hide_token = Hide token in repository URL
cli-info-include_hidden = Count hidden files and directories
cli-info-tipe-short = Filters output by language type (default: ${def}) (possible values: {$pos})
cli-info-tipe-long =
Filters output by language type
(default: ${def})
(possible values: {$pos})
# TEXT FORMATTING
cli-text-heading = TEXT FORMATTING
cli-text-colors-short = Changes the text colors (X X X...)
cli-text-colors-long =
Changes the text colors (X X X...)
Goes in order of title, ~, underline, subtitle, colon, and info
For example:
'--text-colors 9 10 11 12 13 14'
cli-text-iso_time = Use ISO 8601 formatted timestamps
cli-text-number_separator-short = Which thousands SEPARATOR to use (defautl: ${def}) (possible values: {$pos})
cli-text-number_separator-long =
Which thousands SEPARATOR to use
(default: {$def})
(possible values: {$pos})
cli-text-no_bold = Turns off bold formatting
# ASCII
cli-ascii-heading = ASCII
cli-ascii-ascii_input-short = Takes a non-empty STRING as input to replace the ASCII logo
cli-ascii-ascii_input-long =
Takes a non-empty STRING as input to replace the ASCII logo
It is possible to pass a generated STRING by command substitution
For example:
'--ascii-input "$(fortune | cowsay -W 25)"'
cli-ascii-ascii_colors = Colors (X X X...) to print the ascii art
cli-ascii-ascii_language = Which LANGUAGE's ascii art to print
cli-ascii-true_color-short = Specify when to use true color (default: {$def}) (possible values: {$pos})
cli-ascii-true_color-long =
Specify when to use true color
If set to auto: true color will be enabled if supported by the terminal
(default: {$def})
(possible values: {$pos})
# IMAGE
cli-image-heading = IMAGE
cli-image-image = Path to the IMAGE file
cli-image-image_protocol-short = Which image PROTOCOL to use (possible values: {$pos})
cli-image-image_protocol-long =
Which image PROTOCOL to use
(possible values: {$pos})
cli-image-color_resolution-short = VALUE of color resolution to use with SIXEL backend (default: {$def}) (possible values: {$pos})
cli-image-color_resolution-long =
VALUE of color resolution to use with SIXEL backend
(default: {$def})
(possible values: {$pos})
# VISUALS
cli-visuals-heading = VISUALS
cli-visuals-no_color_palette = Hides the color palette
cli-visuals-no_art = Hides the ascii art or image if provided
cli-visuals-nerd_fonts =
Use Nerd Font icons
Replaces language chips with Nerd Font icons
# DEVELOPER
cli-dev-heading = DEVELOPER
cli-dev-output-short = Outputs Onefetch in a specific format (possible values: {$def})
cli-dev-output-long =
Outputs Onefetch in a specific format
(possible values: {$def})
cli-dev-completion-short = If provided, outputs the completion file for given SHELL (possible values: {$def})
cli-dev-completion-long =
If provided, outputs the completion file for given SHELL
(possible values: {$def})
# OTHER
cli-other-heading = OTHER
cli-other-languages = Prints out supported languages
cli-other-package_managers = Prints out supported package managers

152
locales/ru-RU/cli.ftl

@ -0,0 +1,152 @@ @@ -0,0 +1,152 @@
cli-about = Инструмент командной строки для получения информации о Git
cli-usage-header = Использование
cli-arguments-header = Аргументы
cli-arguments-input = Запустить так, как будто onefetch был запущен в <ввод> вместо текущего рабочего каталога
cli-options-header = Опции
cli-options-help = Показать помощь { $short ->
[true] (подробнее с '--help')
*[false] (кратко с '-h')
}
cli-options-version = Показать версию
# Value name
cli-value-input = ВВОД
cli-value-num = КОЛ-ВО
cli-value-field = ПОЛЕ
cli-value-regex = РЕГ. ВЫРАЖЕНИЕ
cli-value-exclude = ИСКЛЮЧЕННОЕ
cli-value-type = ТИП
cli-value-separator = РАЗДЕЛИТЕЛЬ
cli-value-string = СТРОКА
cli-value-language = ЯЗЫК
cli-value-when = КОГДА
cli-value-image = ИЗОБРАЖЕНИЕ
cli-value-protocol = ПРОТОКОЛ
cli-value-value = ЗНАЧЕНИЕ
cli-value-format = ФОРМАТ
cli-value-shell = ОБОЛОЧКА
# INFO
cli-info-heading = ИНФОРМАЦИЯ
cli-info-disabled_fields = Позволяет отключить отображение ПОЛЯ(ПОЛЕЙ) в выводе
cli-info-no_title = Скрывает заголовок
cli-info-number_of_authors-short = Максимальное КОЛ-ВО авторов для отображения (по умолчанию: {$def})
cli-info-number_of_authors-long =
Максимальное КОЛ-ВО авторов для отображения
(по умолчанию: {$def})
cli-info-number_of_languages-short = Максимальное КОЛ-ВО языков для отображения (по умолчанию: {$def})
cli-info-number_of_languages-long =
Максимальное КОЛ-ВО языков для отображения
(по умолчанию: {$def})
cli-info-number_of_file_churns-short = Максимальное КОЛ-ВО изменений файлов для отображения (по умолчанию: {$def})
cli-info-number_of_file_churns-long =
Максимальное КОЛ-ВО изменений файлов для отображения
(по умолчанию: {$def})
cli-info-churn_pool_size-short = Минимальное КОЛ-ВО коммитов от HEAD, используемых для вычисления сводки изменений
cli-info-churn_pool_size-long =
Минимальное КОЛ-ВО коммитов от HEAD, используемых для вычисления сводки изменений
По умолчанию фактическое значение недетерминировано из-за вычислений на основе времени
и будет отображаться под заголовком информации "Изменения (КОЛ-ВО)"
cli-info-exclude = Игнорировать все файлы и каталоги, соответствующие ИСКЛЮЧЕННОМУ
cli-info-no_bots = Исключить коммиты [ботов]. Используйте <РЕГ. ВЫРАЖЕНИЕ> для переопределения шаблона по умолчанию
cli-info-no_merges = Игнорировать коммиты слияния
cli-info-email = Показать адрес электронной почты каждого автора
cli-info-http_url = Отображать URL репозитория как HTTP
cli-info-hide_token = Скрыть токен в URL репозитория
cli-info-include_hidden = Учитывать скрытые файлы и каталоги
cli-info-tipe-short = Фильтровать вывод по типу языка (по умолчанию: {$def}) (возможные значения: {$pos})
cli-info-tipe-long =
Фильтровать вывод по типу языка
(по умолчанию: {$def})
(возможные значения: {$pos})
# TEXT FORMATTING
cli-text-heading = ФОРМАТИРОВАНИЕ ТЕКСТА
cli-text-colors-short = Изменяет цвета текста (X X X...)
cli-text-colors-long =
Изменяет цвета текста (X X X...)
Идет в порядке заголовка, ~, подчеркивания, подзаголовка, двоеточия и информации
Например:
'--text-colors 9 10 11 12 13 14'
cli-text-iso_time = Использовать временные метки в формате ISO 8601
cli-text-number_separator-short = Какой РАЗДЕЛИТЕЛЬ тысяч использовать (по умолчанию: {$def}) (возможные значения: {$pos})
cli-text-number_separator-long =
Какой РАЗДЕЛИТЕЛЬ тысяч использовать
(по умолчанию: {$def})
(возможные значения: {$pos})
cli-text-no_bold = Отключает жирное форматирование
# ASCII
cli-ascii-heading = ASCII
cli-ascii-ascii_input-short = Принимает непустую СТРОКУ в качестве входных данных для замены ASCII логотипа
cli-ascii-ascii_input-long =
Принимает непустую СТРОКУ в качестве входных данных для замены ASCII логотипа
Можно передать сгенерированную СТРОКУ с помощью подстановки команд
Например:
'--ascii-input "$(fortune | cowsay -W 25)"'
cli-ascii-ascii_colors = Цвета (X X X...) для печати ASCII арта
cli-ascii-ascii_language = ASCII арт какого ЯЗЫКА печатать
cli-ascii-true_color-short = Указать, когда использовать true-color (по умолчанию: {$def}) (возможные значения: {$pos})
cli-ascii-true_color-long =
Указать, когда использовать true-color
Если установлено в auto: true-color будет включен, если он поддерживается терминалом
(по умолчанию: {$def})
(возможные значения: {$pos})
# IMAGE
cli-image-heading = ИЗОБРАЖЕНИЕ
cli-image-image = Путь к файлу ИЗОБРАЖЕНИЯ
cli-image-image_protocol-short = Какой ПРОТОКОЛ изображения использовать (возможные значения: {$pos})
cli-image-image_protocol-short =
Какой ПРОТОКОЛ изображения использовать
(возможные значения: ${pos})
cli-image-color_resolution-short = ЗНАЧЕНИЕ разрешения цвета, используемого с бэкендом SIXEL (по умолчанию: {$def}) (возможные значения: {$pos})
cli-image-color_resolution-long =
ЗНАЧЕНИЕ разрешения цвета, используемого с бэкендом SIXEL
(по умолчанию: {$def})
(возможные значения: {$pos})
# VISUALS
cli-visuals-heading = ВИЗУАЛЬНЫЕ ЭЛЕМЕНТЫ
cli-visuals-no_color_palette = Скрывает цветовую палитру
cli-visuals-no_art = Скрывает ASCII арт или изображение, если оно предоставлено
cli-visuals-nerd_fonts =
Использовать иконки Nerd Font
Заменяет языковые чипы иконками Nerd Font
# not sure if ↑ this ↑ is right translation for "chips"
# DEVELOPER
cli-dev-heading = ДЛЯ РАЗРАБОТЧИКОВ
cli-dev-output-short = Выводит Onefetch в определенном формате (возможные значения: {$pos})
cli-dev-output-long =
Выводит Onefetch в определенном формате
(возможные значения: {$pos})
cli-dev-completion-short = Выводит файл автозаполнения для указанной ОБОЛОЧКИ (возможные значения: {$pos})
cli-dev-completion-long =
Выводит файл автозаполнения для указанной ОБОЛОЧКИ
(возможные значения: {$pos})
# OTHER
cli-other-heading = ПРОЧЕЕ
cli-other-languages = Выводит поддерживаемые языки
cli-other-package_managers = Выводит поддерживаемые менеджеры пакетов

265
src/cli.rs

@ -1,9 +1,11 @@ @@ -1,9 +1,11 @@
use crate::i18n::locale_keys::cli::*;
use crate::info::langs::language::{Language, LanguageType};
use crate::info::utils::info_field::InfoType;
use crate::tr;
use crate::ui::printer::SerializationFormat;
use anyhow::Result;
use clap::builder::PossibleValuesParser;
use clap::builder::TypedValueParser as _;
use clap::builder::{PossibleValuesParser, Styles};
use clap::{value_parser, Args, Command, Parser, ValueHint};
use clap_complete::{generate, Generator, Shell};
use num_format::CustomFormat;
@ -20,13 +22,66 @@ use strum::IntoEnumIterator; @@ -20,13 +22,66 @@ use strum::IntoEnumIterator;
const COLOR_RESOLUTIONS: [&str; 5] = ["16", "32", "64", "128", "256"];
pub const NO_BOTS_DEFAULT_REGEX_PATTERN: &str = r"(?:-|\s)[Bb]ot$|\[[Bb]ot\]";
// TODO: check if short help requested more efficiently
use std::sync::LazyLock;
static IS_SHORT: LazyLock<bool> = LazyLock::new(|| {
let args = std::env::args();
let mut v = false;
for value in args {
if value == "-h" {
v = true;
break;
} else if value == "--help" {
break;
} else {
}
}
v
});
#[derive(Clone, Debug, Parser, PartialEq, Eq)]
#[command(version, about)]
#[command(styles = clap_cargo::style::CLAP_STYLING)]
#[command(
about = tr!(ABOUT),
version,
disable_help_flag = true,
disable_version_flag = true,
help_template = format!("\
{{before-help}}{{about-with-newline}}\
\n{}{}:{} {{usage}}
\n{{all-args}}{{after-help}}\
",
Styles::default().get_usage().render(),
tr!(usage::HEADER),
Styles::default().get_usage().render_reset()
),
next_help_heading = tr!(arguments::HEADER),
override_usage = format!("onefetch [{}] [{}]", tr!(options::HEADER).to_owned().to_uppercase(), tr!(value::INPUT))
)]
pub struct CliOptions {
/// Run as if onefetch was started in <input> instead of the current working directory
#[arg(default_value = ".", hide_default_value = true, value_hint = ValueHint::DirPath)]
#[arg(
default_value = ".",
hide_default_value = true,
value_hint = ValueHint::DirPath,
help = tr!(arguments::INPUT),
value_name = tr!(value::INPUT)
)]
pub input: PathBuf,
#[arg(
action = if *IS_SHORT { clap::ArgAction::HelpShort } else { clap::ArgAction::HelpLong },
long,
short,
help = tr!(options::HELP, short => &*IS_SHORT),
help_heading = tr!(options::HEADER)
)]
pub help: Option<bool>,
#[arg(
action = clap::ArgAction::Version,
long,
short = 'V',
help = tr!(options::VERSION),
help_heading = tr!(options::HEADER)
)]
pub version: Option<bool>,
#[command(flatten)]
pub info: InfoCliOptions,
#[command(flatten)]
@ -44,201 +99,223 @@ pub struct CliOptions { @@ -44,201 +99,223 @@ pub struct CliOptions {
}
#[derive(Clone, Debug, Args, PartialEq, Eq)]
#[command(next_help_heading = "INFO")]
#[command(next_help_heading = tr!(info::HEADING))]
pub struct InfoCliOptions {
/// Allows you to disable FIELD(s) from appearing in the output
#[arg(
long,
short,
help = tr!(info::DISABLED_FIELDS),
num_args = 1..,
hide_possible_values = true,
value_enum,
value_name = "FIELD"
value_name = tr!(value::FIELD)
)]
pub disabled_fields: Vec<InfoType>,
/// Hides the title
#[arg(long)]
#[arg(long, help = tr!(info::NO_TITLE))]
pub no_title: bool,
/// Maximum NUM of authors to be shown
#[arg(long, default_value_t = 3usize, value_name = "NUM")]
#[arg(long, default_value_t = 3usize, value_name = tr!(value::NUM), hide_default_value = true)]
#[arg(
help = tr!(info::number_of_authors::SHORT, def => 3),
long_help = tr!(info::number_of_authors::LONG, def => 3),
hide_default_value = true
)]
pub number_of_authors: usize,
/// Maximum NUM of languages to be shown
#[arg(long, default_value_t = 6usize, value_name = "NUM")]
#[arg(long, default_value_t = 6usize, value_name = tr!(value::NUM))]
#[arg(
help = tr!(info::number_of_languages::SHORT, def => 6),
long_help = tr!(info::number_of_languages::LONG, def => 6),
hide_default_value = true
)]
pub number_of_languages: usize,
/// Maximum NUM of file churns to be shown
#[arg(long, default_value_t = 3usize, value_name = "NUM")]
#[arg(long, default_value_t = 3usize, value_name = tr!(value::NUM))]
#[arg(
help = tr!(info::number_of_file_churns::SHORT, def => 3),
long_help = tr!(info::number_of_file_churns::LONG, def => 3),
hide_default_value = true
)]
pub number_of_file_churns: usize,
/// Minimum NUM of commits from HEAD used to compute the churn summary
///
/// By default, the actual value is non-deterministic due to time-based computation
/// and will be displayed under the info title "Churn (NUM)"
#[arg(long, value_name = "NUM")]
#[arg(long, value_name = tr!(value::NUM))]
#[arg(
help = tr!(info::churn_pool_size::SHORT),
long_help = tr!(info::churn_pool_size::LONG)
)]
pub churn_pool_size: Option<usize>,
/// Ignore all files & directories matching EXCLUDE
#[arg(long, short, num_args = 1..)]
#[arg(long, short, num_args = 1.., help = tr!(info::EXCLUDE), value_name = tr!(value::EXCLUDE))]
pub exclude: Vec<String>,
/// Exclude [bot] commits. Use <REGEX> to override the default pattern
#[arg(
long,
num_args = 0..=1,
require_equals = true,
default_missing_value = NO_BOTS_DEFAULT_REGEX_PATTERN,
value_name = "REGEX"
value_name = tr!(value::REGEX),
help = tr!(info::NO_BOTS)
)]
pub no_bots: Option<MyRegex>,
/// Ignores merge commits
#[arg(long)]
#[arg(long, help = tr!(info::NO_MERGES))]
pub no_merges: bool,
/// Show the email address of each author
#[arg(long, short = 'E')]
#[arg(long, short = 'E', help = tr!(info::EMAIL))]
pub email: bool,
/// Display repository URL as HTTP
#[arg(long)]
#[arg(long, help = tr!(info::HTTP_URL))]
pub http_url: bool,
/// Hide token in repository URL
#[arg(long)]
#[arg(long, help = tr!(info::HIDE_TOKEN))]
pub hide_token: bool,
/// Count hidden files and directories
#[arg(long)]
#[arg(long, help = tr!(info::INCLUDE_HIDDEN))]
pub include_hidden: bool,
/// Filters output by language type
#[arg(
long,
num_args = 1..,
value_name = tr!(value::TYPE),
default_values = &["programming", "markup"],
short = 'T',
value_enum,
)]
#[arg(
help = tr!(info::tipe::SHORT, def => "programming, markup", pos => "programming, markup, prose, data"),
long_help = tr!(info::tipe::LONG, def => "programming, markup", pos => "programming, markup, prose, data"),
hide_default_value = true,
hide_possible_values = true,
)]
pub r#type: Vec<LanguageType>,
}
#[derive(Clone, Debug, Args, PartialEq, Eq)]
#[command(next_help_heading = "ASCII")]
#[command(next_help_heading = tr!(ascii::HEADING))]
pub struct AsciiCliOptions {
/// Takes a non-empty STRING as input to replace the ASCII logo
///
/// It is possible to pass a generated STRING by command substitution
///
/// For example:
///
/// '--ascii-input "$(fortune | cowsay -W 25)"'
#[arg(long, value_name = "STRING", value_hint = ValueHint::CommandString)]
#[arg(long, value_name = tr!(value::STRING), value_hint = ValueHint::CommandString)]
#[arg(
help = tr!(ascii::ascii_input::SHORT),
long_help = tr!(ascii::ascii_input::LONG)
)]
pub ascii_input: Option<String>,
/// Colors (X X X...) to print the ascii art
#[arg(
long,
num_args = 1..,
value_name = "X",
short = 'c',
value_parser = value_parser!(u8).range(..16),
help = tr!(ascii::ASCII_COLORS)
)]
pub ascii_colors: Vec<u8>,
/// Which LANGUAGE's ascii art to print
#[arg(
long,
short,
value_name = "LANGUAGE",
value_name = tr!(value::LANGUAGE),
value_enum,
hide_possible_values = true
hide_possible_values = true,
help = tr!(ascii::ASCII_LANGUAGE)
)]
pub ascii_language: Option<Language>,
/// Specify when to use true color
///
/// If set to auto: true color will be enabled if supported by the terminal
#[arg(long, default_value = "auto", value_name = "WHEN", value_enum)]
#[arg(long, value_name = tr!(value::WHEN), value_enum, default_value = "auto")]
#[arg(
help = tr!(ascii::true_color::SHORT, def => "auto", pos => "auto, never, always"),
long_help = tr!(ascii::true_color::LONG, def => "auto", pos => "auto, never, always"),
hide_possible_values = true,
hide_default_value = true
)]
pub true_color: When,
}
#[derive(Clone, Debug, Args, PartialEq, Eq)]
#[command(next_help_heading = "IMAGE")]
#[command(next_help_heading = tr!(image::HEADING))]
pub struct ImageCliOptions {
/// Path to the IMAGE file
#[arg(long, short, value_hint = ValueHint::FilePath)]
#[arg(long, short, value_name = tr!(value::IMAGE), value_hint = ValueHint::FilePath, help = tr!(image::IMAGE))]
pub image: Option<PathBuf>,
/// Which image PROTOCOL to use
#[arg(long, value_enum, requires = "image", value_name = "PROTOCOL")]
#[arg(long, value_enum, requires = "image", value_name = tr!(value::PROTOCOL))]
#[arg(
help = tr!(image::image_protocol::SHORT, pos => "kitty, sixel, iterm"),
long_help = tr!(image::image_protocol::LONG, pos => "kitty, sixel, iterm"),
hide_possible_values = true
)]
pub image_protocol: Option<ImageProtocol>,
/// VALUE of color resolution to use with SIXEL backend
#[arg(
long,
value_name = "VALUE",
value_name = tr!(value::VALUE),
requires = "image",
default_value_t = 16usize,
value_parser = PossibleValuesParser::new(COLOR_RESOLUTIONS)
.map(|s| s.parse::<usize>().unwrap())
)]
#[arg(
help = tr!(image::color_resolution::SHORT, def => 16, pos => COLOR_RESOLUTIONS.join(", ")),
long_help = tr!(image::color_resolution::LONG, def => 16, pos => COLOR_RESOLUTIONS.join(", ")),
hide_default_value = true,
hide_possible_values = true
)]
pub color_resolution: usize,
}
#[derive(Clone, Debug, Args, PartialEq, Eq)]
#[command(next_help_heading = "TEXT FORMATTING")]
#[command(next_help_heading = tr!(text::HEADING))]
pub struct TextForamttingCliOptions {
/// Changes the text colors (X X X...)
///
/// Goes in order of title, ~, underline, subtitle, colon, and info
///
/// For example:
///
/// '--text-colors 9 10 11 12 13 14'
#[arg(
long,
short,
value_name = "X",
value_parser = value_parser!(u8).range(..16),
num_args = 1..=6
num_args = 1..=6,
)]
#[arg(
help = tr!(text::colors::SHORT),
long_help = tr!(text::colors::LONG)
)]
pub text_colors: Vec<u8>,
/// Use ISO 8601 formatted timestamps
#[arg(long, short = 'z')]
#[arg(long, short = 'z', help = tr!(text::ISO_TIME))]
pub iso_time: bool,
/// Which thousands SEPARATOR to use
#[arg(long, value_name = "SEPARATOR", default_value = "plain", value_enum)]
#[arg(long, value_name = tr!(value::SEPARATOR), value_enum, default_value = "plain")]
#[arg(
help = tr!(text::number_separator::SHORT, def => "plain", pos => "plain, comma, space, underscore"),
long_help = tr!(text::number_separator::LONG, def => "plain", pos => "plain, comma, space, underscore"),
hide_default_value = true,
hide_possible_values = true,
)]
pub number_separator: NumberSeparator,
/// Turns off bold formatting
#[arg(long)]
#[arg(long, help = tr!(text::NO_BOLD))]
pub no_bold: bool,
}
#[derive(Clone, Debug, Args, PartialEq, Eq, Default)]
#[command(next_help_heading = "VISUALS")]
#[command(next_help_heading = tr!(visuals::HEADING))]
pub struct VisualsCliOptions {
/// Hides the color palette
#[arg(long)]
#[arg(long, help = tr!(visuals::NO_COLOR_PALETTE))]
pub no_color_palette: bool,
/// Hides the ascii art or image if provided
#[arg(long)]
#[arg(long, help = tr!(visuals::NO_ART))]
pub no_art: bool,
/// Use Nerd Font icons
///
/// Replaces language chips with Nerd Font icons
#[arg(long)]
#[arg(long, help = tr!(visuals::NERD_FONTS))]
pub nerd_fonts: bool,
}
#[derive(Clone, Debug, Args, PartialEq, Eq, Default)]
#[command(next_help_heading = "DEVELOPER")]
#[command(next_help_heading = tr!(dev::HEADING))]
pub struct DeveloperCliOptions {
/// Outputs Onefetch in a specific format
#[arg(long, short, value_name = "FORMAT", value_enum)]
#[arg(long, short, value_name = tr!(value::FORMAT), value_enum)]
#[arg(
help = tr!(dev::output::SHORT, pos => "json, yaml"),
long_help = tr!(dev::output::LONG, pos => "json, yaml"),
hide_possible_values = true
)]
pub output: Option<SerializationFormat>,
/// If provided, outputs the completion file for given SHELL
#[arg(long = "generate", value_name = "SHELL", value_enum)]
#[arg(long = "generate", value_name = tr!(value::SHELL), value_enum)]
#[arg(
help = tr!(dev::completion::SHORT, pos => "bash, elvish, fish, powershell, zsh"),
long_help = tr!(dev::completion::LONG, pos => "bash, elvish, fish, powershell, zsh"),
hide_possible_values = true,
)]
pub completion: Option<Shell>,
}
#[derive(Clone, Debug, Args, PartialEq, Eq, Default)]
#[command(next_help_heading = "OTHER")]
#[command(next_help_heading = tr!(other::HEADING))]
pub struct OtherCliOptions {
/// Prints out supported languages
#[arg(long, short)]
#[arg(long, short, help = tr!(other::LANGUAGES))]
pub languages: bool,
/// Prints out supported package managers
#[arg(long, short)]
#[arg(long, short, help = tr!(other::PACKAGE_MANAGERS))]
pub package_managers: bool,
}
impl Default for CliOptions {
fn default() -> CliOptions {
CliOptions {
help: None,
version: None,
input: PathBuf::from("."),
info: InfoCliOptions::default(),
text_formatting: TextForamttingCliOptions::default(),

58
src/i18n.rs

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
use std::sync::LazyLock;
use anyhow::Context as _;
use i18n_embed::fluent::FluentLanguageLoader;
use i18n_embed::DefaultLocalizer;
use i18n_embed::DesktopLanguageRequester;
use i18n_embed::LanguageLoader;
use i18n_embed::Localizer as _;
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
#[folder = "__locales_compiled"]
struct Localizations;
include!(concat!(env!("OUT_DIR"), "/locales_consts.rs"));
pub static LOADER: LazyLock<FluentLanguageLoader> = LazyLock::new(|| {
let loader = i18n_embed::fluent::fluent_language_loader!();
loader.load_fallback_language(&Localizations).unwrap();
loader
});
fn localizer() -> DefaultLocalizer<'static> {
DefaultLocalizer::new(&*LOADER, &Localizations)
}
pub fn init() -> anyhow::Result<()> {
let localizer = localizer();
let requested = DesktopLanguageRequester::requested_languages();
localizer
.select(&requested)
.context("Failed to set languages")?;
Ok(())
}
#[macro_export]
macro_rules! tr {
($id:literal) => {{
i18n_embed_fl::fl!($crate::i18n::LOADER, $id)
}};
($id:literal, $($args:expr),*) => {{
i18n_embed_fl::fl!($crate::i18n::LOADER, $id, $($args),*)
}};
($id:expr) => {{
$crate::i18n::LOADER.get($id)
}};
($id:expr, $($key:expr => $value:expr),*) => {{
let mut args = std::collections::HashMap::new();
$(
args.insert(stringify!($key), $value.to_string());
)*
$crate::i18n::LOADER.get_args($id, args)
}};
}

1
src/lib.rs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
// Lib is present to allow for benchmarks and integration tests
pub mod cli;
pub mod i18n;
pub mod info;
pub mod ui;

10
src/main.rs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
use anyhow::Result;
use clap::{CommandFactory, Parser};
use clap_i18n_richformatter::{init_clap_rich_formatter_localizer, ClapI18nRichFormatter};
use human_panic::setup_panic;
use onefetch::cli::{self, CliOptions};
use onefetch::info::build_info;
@ -10,11 +11,18 @@ use std::io; @@ -10,11 +11,18 @@ use std::io;
fn main() -> Result<()> {
setup_panic!();
onefetch::i18n::init()?;
init_clap_rich_formatter_localizer();
#[cfg(windows)]
enable_ansi_support::enable_ansi_support()?;
let cli_options = cli::CliOptions::parse();
let cli_options = cli::CliOptions::try_parse()
.map_err(|e| {
let e = e.apply::<ClapI18nRichFormatter>();
e.exit()
})
.unwrap();
if cli_options.other.languages {
return cli::print_supported_languages();

Loading…
Cancel
Save