diff --git a/Cargo.lock b/Cargo.lock index 10cf781..c415853 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,11 +59,15 @@ dependencies = [ "flate2", "gumdrop", "hex", + "i18n-embed", + "i18n-embed-fl", + "lazy_static", "log", "man", "p256", "pcsc", "rand", + "rust-embed", "sha2", "which", "x509", @@ -130,6 +134,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.9.0" @@ -265,6 +275,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "dashmap" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8858831f7781322e539ea39e72449c46b059638250c14344fec8d0aa6e539c" +dependencies = [ + "cfg-if", + "num_cpus", + "parking_lot", +] + [[package]] name = "data-encoding" version = "2.3.2" @@ -408,6 +429,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "find-crate" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" +dependencies = [ + "toml", +] + [[package]] name = "flate2" version = "1.0.22" @@ -420,6 +450,50 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fluent" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f69378194459db76abd2ce3952b790db103ceb003008d3d50d97c41ff847a7" +dependencies = [ + "fluent-bundle", + "unic-langid", +] + +[[package]] +name = "fluent-bundle" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash", + "self_cell", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78" +dependencies = [ + "thiserror", +] + [[package]] name = "generic-array" version = "0.14.5" @@ -513,6 +587,75 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "i18n-config" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62affcd43abfb51f3cbd8736f9407908dc5b44fc558a9be07460bbfd104d983" +dependencies = [ + "log", + "serde", + "serde_derive", + "thiserror", + "toml", + "unic-langid", +] + +[[package]] +name = "i18n-embed" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f21ed76e44de8ac3dfa36bb37ab2e6480be0dc75c612474949be1f3cb2c253" +dependencies = [ + "fluent", + "fluent-langneg", + "fluent-syntax", + "i18n-embed-impl", + "intl-memoizer", + "lazy_static", + "locale_config", + "log", + "parking_lot", + "rust-embed", + "thiserror", + "unic-langid", + "walkdir", +] + +[[package]] +name = "i18n-embed-fl" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420a9718ef9d0ab727840a398e25408ea0daff9ba3c681707ba05485face98e" +dependencies = [ + "dashmap", + "find-crate", + "fluent", + "fluent-syntax", + "i18n-config", + "i18n-embed", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "strsim", + "syn", + "unic-langid", +] + +[[package]] +name = "i18n-embed-impl" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0db2330e035808eb064afb67e6743ddce353763af3e0f2bdfc2476e00ce76136" +dependencies = [ + "find-crate", + "i18n-config", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "instant" version = "0.1.12" @@ -522,6 +665,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "intl-memoizer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b18f988384267d7066cc2be425e6faf352900652c046b6971d2e228d3b1c5ecf" +dependencies = [ + "tinystr", + "unic-langid", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -543,6 +706,29 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db" +[[package]] +name = "locale_config" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934" +dependencies = [ + "lazy_static", + "objc", + "objc-foundation", + "regex", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg 1.1.0", + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -552,6 +738,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "man" version = "0.3.0" @@ -654,6 +849,45 @@ dependencies = [ "libm", ] +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "oid-registry" version = "0.2.0" @@ -695,6 +929,29 @@ dependencies = [ "elliptic-curve", ] +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "pbkdf2" version = "0.9.0" @@ -779,6 +1036,30 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.36" @@ -888,6 +1169,46 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rust-embed" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a17e5ac65b318f397182ae94e532da0ba56b88dd1200b774715d36c4943b1c3" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756feca3afcbb1487a1d01f4ecd94cf8ec98ea074c55a69e7136d29fb6166029" +dependencies = [ + "sha2", + "walkdir", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -897,6 +1218,21 @@ dependencies = [ "nom", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "secrecy" version = "0.8.0" @@ -906,11 +1242,31 @@ dependencies = [ "zeroize", ] +[[package]] +name = "self_cell" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af" + [[package]] name = "serde" version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "sha-1" @@ -969,6 +1325,12 @@ dependencies = [ "der", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.4.1" @@ -1070,12 +1432,55 @@ dependencies = [ "winapi", ] +[[package]] +name = "tinystr" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1" + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "type-map" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46" +dependencies = [ + "rustc-hash", +] + [[package]] name = "typenum" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "unic-langid" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73328fcd730a030bdb19ddf23e192187a6b01cd98be6d3140622a89129459ce5" +dependencies = [ + "unic-langid-impl", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a4a8eeaf0494862c1404c95ec2f4c33a2acff5076f64314b465e3ddae1b934d" +dependencies = [ + "serde", + "tinystr", +] + [[package]] name = "unicode-width" version = "0.1.9" @@ -1113,6 +1518,17 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -1161,6 +1577,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "x509" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 83df6b9..49ef1b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,12 @@ x509 = "0.2" x509-parser = "0.12" yubikey = { version = "0.5", features = ["untested"] } +# Translations +i18n-embed = { version = "0.13", features = ["desktop-requester", "fluent-system"] } +i18n-embed-fl = "0.6" +lazy_static = "1" +rust-embed = "6" + [dev-dependencies] flate2 = "1" man = "0.3" diff --git a/i18n.toml b/i18n.toml new file mode 100644 index 0000000..40d065c --- /dev/null +++ b/i18n.toml @@ -0,0 +1,4 @@ +fallback_language = "en-US" + +[fluent] +assets_dir = "i18n" diff --git a/i18n/en-US/age_plugin_yubikey.ftl b/i18n/en-US/age_plugin_yubikey.ftl new file mode 100644 index 0000000..0512a6d --- /dev/null +++ b/i18n/en-US/age_plugin_yubikey.ftl @@ -0,0 +1,13 @@ +# Copyright 2022 Jack Grigg +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +### Localization for strings in age-plugin-yubikey + +-age = age +-yubikey = YubiKey +-age-plugin-yubikey = age-plugin-yubikey diff --git a/src/main.rs b/src/main.rs index 743cc56..6da5c38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,12 @@ use std::io::{self, Write}; use age_plugin::run_state_machine; use dialoguer::{Confirm, Input, Select}; use gumdrop::Options; +use i18n_embed::{ + fluent::{fluent_language_loader, FluentLanguageLoader}, + DesktopLanguageRequester, +}; +use lazy_static::lazy_static; +use rust_embed::RustEmbed; use yubikey::{ certificate::PublicKeyInfo, piv::{RetiredSlotId, SlotId}, @@ -52,6 +58,23 @@ const USABLE_SLOTS: [RetiredSlotId; 20] = [ RetiredSlotId::R20, ]; +#[derive(RustEmbed)] +#[folder = "i18n"] +struct Translations; + +const TRANSLATIONS: Translations = Translations {}; + +lazy_static! { + static ref LANGUAGE_LOADER: FluentLanguageLoader = fluent_language_loader!(); +} + +#[macro_export] +macro_rules! fl { + ($message_id:literal) => {{ + i18n_embed_fl::fl!($crate::LANGUAGE_LOADER, $message_id) + }}; +} + #[derive(Debug, Options)] struct PluginOptions { #[options(help = "Print this help message and exit.")] @@ -301,6 +324,12 @@ fn main() -> Result<(), Error> { .parse_default_env() .init(); + let requested_languages = DesktopLanguageRequester::requested_languages(); + i18n_embed::select(&*LANGUAGE_LOADER, &TRANSLATIONS, &requested_languages).unwrap(); + // Unfortunately the common Windows terminals don't support Unicode Directionality + // Isolation Marks, so we disable them for now. + LANGUAGE_LOADER.set_use_isolating(false); + let opts = PluginOptions::parse_args_default_or_exit(); if [opts.generate, opts.identity, opts.list, opts.list_all]