From 4cbe35a28662fa9d7a3b080b4800358113d6456c Mon Sep 17 00:00:00 2001
From: Myriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com>
Date: Sat, 15 Mar 2025 10:38:07 +0800
Subject: [PATCH] feat: employ l10n to tinymist-cli and vscode extension
(#1505)
* feat: runtime translation
* feat: poc of rust translation
* feat: clean up implementation
* feat: initialize correctly
* dev: remove dirty log
* dev: rename l10nMsg
* fix: desc
* feat: update assets building
* feat: update assets building
* build: update cargo.lock
* fix: warnings
* fix: warnings
* dev: expose api
* fix: compile error
* fix: compile errors in scripts
---
.github/workflows/release-asset-crate.yml | 3 +-
.github/workflows/release-vscode.yml | 5 +-
Cargo.lock | 16 ++
Cargo.toml | 1 +
crates/tinymist-assets/Cargo.toml | 1 +
crates/tinymist-assets/src/.gitignore | 3 +-
crates/tinymist-assets/src/lib.rs | 7 +
crates/tinymist-derive/Cargo.toml | 3 -
crates/tinymist-l10n/Cargo.toml | 41 ++++
crates/tinymist-l10n/README.md | 3 +
crates/tinymist-l10n/dist.toml | 3 +
crates/tinymist-l10n/src/lib.rs | 251 ++++++++++++++++++++++
crates/tinymist-l10n/src/main.rs | 125 +++++++++++
crates/tinymist-query/Cargo.toml | 1 +
crates/tinymist-query/src/code_lens.rs | 25 ++-
crates/tinymist/Cargo.toml | 15 +-
crates/tinymist/src/init.rs | 13 ++
crates/tinymist/src/main.rs | 17 +-
docs/tinymist/configurations.typ | 4 +-
editors/vscode/.gitignore | 3 +-
editors/vscode/.vscodeignore | 1 +
editors/vscode/Configuration.md | 2 +-
editors/vscode/package.json | 1 +
editors/vscode/scripts/config-man.mjs | 10 +-
editors/vscode/src/features/preview.ts | 3 +-
editors/vscode/src/l10n.ts | 5 +
eslint.config.mjs | 4 +-
locales/tinymist-rt.toml | 22 ++
locales/tinymist-vscode-rt.toml | 6 +
package.json | 5 +-
scripts/build-l10n.mjs | 47 ++--
scripts/link-docs.mjs | 24 +--
syntaxes/textmate/main.mts | 7 +-
33 files changed, 615 insertions(+), 62 deletions(-)
create mode 100644 crates/tinymist-l10n/Cargo.toml
create mode 100644 crates/tinymist-l10n/README.md
create mode 100644 crates/tinymist-l10n/dist.toml
create mode 100644 crates/tinymist-l10n/src/lib.rs
create mode 100644 crates/tinymist-l10n/src/main.rs
create mode 100644 editors/vscode/src/l10n.ts
create mode 100644 locales/tinymist-rt.toml
create mode 100644 locales/tinymist-vscode-rt.toml
diff --git a/.github/workflows/release-asset-crate.yml b/.github/workflows/release-asset-crate.yml
index 9fc3946a..d44b89bb 100644
--- a/.github/workflows/release-asset-crate.yml
+++ b/.github/workflows/release-asset-crate.yml
@@ -35,9 +35,10 @@ jobs:
# uses: Swatinem/rust-cache@v2
- name: Install deps
run: yarn install
- - name: Check and build typst-preview
+ - name: Check and build assets
run: |
yarn build:preview
+ yarn build:l10n
- name: Publish crates
run: |
cargo publish --allow-dirty --no-verify -p tinymist-assets || true
diff --git a/.github/workflows/release-vscode.yml b/.github/workflows/release-vscode.yml
index ca7e5da5..2f6ca576 100644
--- a/.github/workflows/release-vscode.yml
+++ b/.github/workflows/release-vscode.yml
@@ -52,10 +52,11 @@ jobs:
node-version: 22
- name: Install deps
run: yarn install
- - name: Check and build typst-preview
+ - uses: Swatinem/rust-cache@v2
+ - name: Check and build assets
run: |
yarn build:preview
- - uses: Swatinem/rust-cache@v2
+ yarn build:l10n
- run: cargo clippy --workspace --all-targets
- run: cargo fmt --check --all
- run: cargo doc --workspace --no-deps
diff --git a/Cargo.lock b/Cargo.lock
index 44d3f130..446b5b09 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4027,6 +4027,7 @@ dependencies = [
"temp-env",
"tinymist-assets 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tinymist-core",
+ "tinymist-l10n",
"tinymist-project",
"tinymist-query",
"tinymist-render",
@@ -4105,6 +4106,20 @@ dependencies = [
"syn 2.0.98",
]
+[[package]]
+name = "tinymist-l10n"
+version = "0.13.8"
+dependencies = [
+ "anyhow",
+ "clap",
+ "ecow",
+ "insta",
+ "rayon",
+ "rustc-hash 2.1.1",
+ "serde_json",
+ "walkdir",
+]
+
[[package]]
name = "tinymist-project"
version = "0.13.2"
@@ -4173,6 +4188,7 @@ dependencies = [
"strum",
"tinymist-analysis",
"tinymist-derive",
+ "tinymist-l10n",
"tinymist-project",
"tinymist-std",
"tinymist-world",
diff --git a/Cargo.toml b/Cargo.toml
index 67c89381..a67fdb5a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -187,6 +187,7 @@ typst-shim = { path = "./crates/typst-shim", version = "0.13.2" }
tinymist-core = { path = "./crates/tinymist-core/", version = "0.13.8", default-features = false }
tinymist = { path = "./crates/tinymist/", version = "0.13.8" }
+tinymist-l10n = { path = "./crates/tinymist-l10n/", version = "0.13.8" }
tinymist-query = { path = "./crates/tinymist-query/", version = "0.13.8" }
tinymist-render = { path = "./crates/tinymist-render/", version = "0.13.8" }
typst-preview = { path = "./crates/typst-preview", version = "0.13.8" }
diff --git a/crates/tinymist-assets/Cargo.toml b/crates/tinymist-assets/Cargo.toml
index 203809c1..96f2f08e 100644
--- a/crates/tinymist-assets/Cargo.toml
+++ b/crates/tinymist-assets/Cargo.toml
@@ -14,3 +14,4 @@ include = ["src/**/*"]
[features]
typst-preview = []
+l10n = []
diff --git a/crates/tinymist-assets/src/.gitignore b/crates/tinymist-assets/src/.gitignore
index ad8e3db7..187b6e17 100644
--- a/crates/tinymist-assets/src/.gitignore
+++ b/crates/tinymist-assets/src/.gitignore
@@ -1 +1,2 @@
-typst-preview.html
\ No newline at end of file
+typst-preview.html
+tinymist-rt.toml
\ No newline at end of file
diff --git a/crates/tinymist-assets/src/lib.rs b/crates/tinymist-assets/src/lib.rs
index e07d824c..5c96011e 100644
--- a/crates/tinymist-assets/src/lib.rs
+++ b/crates/tinymist-assets/src/lib.rs
@@ -3,3 +3,10 @@
pub const TYPST_PREVIEW_HTML: &str = include_str!("typst-preview.html");
#[cfg(not(feature = "typst-preview"))]
pub const TYPST_PREVIEW_HTML: &str = "
Typst Preview needs to be built with the `embed-html` feature to work!";
+
+/// If this file is not found, please runs `yarn extract:l10n:rs` to extract the
+/// localization data.
+#[cfg(feature = "l10n")]
+pub const L10N_DATA: &str = include_str!("tinymist-rt.toml");
+#[cfg(not(feature = "l10n"))]
+pub const L10N_DATA: &str = "";
diff --git a/crates/tinymist-derive/Cargo.toml b/crates/tinymist-derive/Cargo.toml
index 1d1a650c..16d2597f 100644
--- a/crates/tinymist-derive/Cargo.toml
+++ b/crates/tinymist-derive/Cargo.toml
@@ -18,6 +18,3 @@ quote.workspace = true
[lib]
proc-macro = true
-
-[features]
-typst-preview = []
diff --git a/crates/tinymist-l10n/Cargo.toml b/crates/tinymist-l10n/Cargo.toml
new file mode 100644
index 00000000..7ee65d07
--- /dev/null
+++ b/crates/tinymist-l10n/Cargo.toml
@@ -0,0 +1,41 @@
+[package]
+name = "tinymist-l10n"
+description = "Localization support for tinymist and typst."
+categories = ["compilers", "command-line-utilities"]
+keywords = ["language", "typst"]
+authors.workspace = true
+version.workspace = true
+license.workspace = true
+edition.workspace = true
+homepage.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+
+[[bin]]
+name = "tinymist-l10n"
+path = "src/main.rs"
+required-features = ["cli"]
+test = false
+doctest = false
+bench = false
+doc = false
+
+[dependencies]
+
+anyhow.workspace = true
+clap = { workspace = true, optional = true }
+ecow.workspace = true
+rayon.workspace = true
+rustc-hash.workspace = true
+serde_json.workspace = true
+walkdir.workspace = true
+
+[dev-dependencies]
+insta.workspace = true
+
+[features]
+default = ["cli"]
+cli = ["clap", "clap/wrap_help"]
+
+[lints]
+workspace = true
diff --git a/crates/tinymist-l10n/README.md b/crates/tinymist-l10n/README.md
new file mode 100644
index 00000000..a00474c2
--- /dev/null
+++ b/crates/tinymist-l10n/README.md
@@ -0,0 +1,3 @@
+# tinymist-l10n
+
+Tinymist's l10n tool.
diff --git a/crates/tinymist-l10n/dist.toml b/crates/tinymist-l10n/dist.toml
new file mode 100644
index 00000000..228c1309
--- /dev/null
+++ b/crates/tinymist-l10n/dist.toml
@@ -0,0 +1,3 @@
+
+[dist]
+dist = false
diff --git a/crates/tinymist-l10n/src/lib.rs b/crates/tinymist-l10n/src/lib.rs
new file mode 100644
index 00000000..eba0014a
--- /dev/null
+++ b/crates/tinymist-l10n/src/lib.rs
@@ -0,0 +1,251 @@
+//! Tinymist's localization library.
+
+use core::panic;
+use std::{
+ borrow::Cow,
+ collections::HashSet,
+ path::Path,
+ sync::{OnceLock, RwLock},
+};
+
+use rayon::{
+ iter::{IntoParallelRefMutIterator, ParallelIterator},
+ str::ParallelString,
+};
+use rustc_hash::FxHashMap;
+
+/// A map of translations.
+pub type TranslationMap = FxHashMap;
+/// A set of translation maps.
+pub type TranslationMapSet = FxHashMap;
+
+static ALL_TRANSLATIONS: OnceLock = OnceLock::new();
+static LOCALE_TRANSLATIONS: RwLock