From 7a57b026a08b68badbdad7810e4b1be8618e00fc Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Wed, 25 Mar 2026 22:20:26 +0800 Subject: [PATCH] feat(wasm-api): port i18n module for plugin and host use (#1898) --- pumpkin-plugin-wit/v0.1.0/i18n.wit | 21 ++++++++++++ pumpkin-plugin-wit/v0.1.0/plugin.wit | 1 + .../loader/wasm/wasm_host/wit/v0_1_0/i18n.rs | 32 +++++++++++++++++++ .../loader/wasm/wasm_host/wit/v0_1_0/mod.rs | 1 + 4 files changed, 55 insertions(+) create mode 100644 pumpkin-plugin-wit/v0.1.0/i18n.wit create mode 100644 pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1_0/i18n.rs diff --git a/pumpkin-plugin-wit/v0.1.0/i18n.wit b/pumpkin-plugin-wit/v0.1.0/i18n.wit new file mode 100644 index 000000000..2d7507437 --- /dev/null +++ b/pumpkin-plugin-wit/v0.1.0/i18n.wit @@ -0,0 +1,21 @@ +interface i18n { + use common.{locale}; + + /// Retrieves a translated string from the host. + /// + /// # Arguments + /// * `key`: The namespaced translation key (e.g. `pumpkin:my_key`). + /// * `locale`: The target locale. + /// + /// # Returns + /// The localized string, falling back to English or the key itself. + translate: func(key: string, locale: locale) -> string; + + /// Loads custom translations from a JSON string. + /// + /// # Arguments + /// * `namespace`: The namespace to associate these keys with. + /// * `json`: A JSON string containing a flat map of translations. + /// * `locale`: The target locale for these translations. + load-translations: func(namespace: string, json: string, locale: locale); +} diff --git a/pumpkin-plugin-wit/v0.1.0/plugin.wit b/pumpkin-plugin-wit/v0.1.0/plugin.wit index 7aa3162c9..487cf32e2 100644 --- a/pumpkin-plugin-wit/v0.1.0/plugin.wit +++ b/pumpkin-plugin-wit/v0.1.0/plugin.wit @@ -12,6 +12,7 @@ world plugin { import text; import command; import context; + import i18n; // This is what the plugin should provide export init-plugin: func(); diff --git a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1_0/i18n.rs b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1_0/i18n.rs new file mode 100644 index 000000000..2e3da9406 --- /dev/null +++ b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1_0/i18n.rs @@ -0,0 +1,32 @@ +use crate::plugin::loader::wasm::wasm_host::{ + state::PluginHostState, + wit::v0_1_0::pumpkin::plugin::{common::Locale as WitLocale, i18n::Host}, +}; +use pumpkin_util::translation::{Locale as UtilLocale, add_translation_file, get_translation}; +use std::str::FromStr; + +impl Host for PluginHostState { + async fn translate(&mut self, key: String, locale: WitLocale) -> String { + let util_locale = wit_to_util_locale(locale); + get_translation(&key, util_locale) + } + + async fn load_translations(&mut self, namespace: String, json: String, locale: WitLocale) { + let util_locale = wit_to_util_locale(locale); + add_translation_file(namespace, json, util_locale); + } +} + +/// Converts a WIT Locale to a pumpkin-util Locale. +fn wit_to_util_locale(wit: WitLocale) -> UtilLocale { + // WIT names are kebab-case (e.g., AfZa -> af-za in .wit, but in generated Rust it might vary) + // We can use the debug representation or a custom mapping. + // Given the amount of variants, we use a string-based approach if possible. + let s = format!("{wit:?}").to_lowercase(); + // pumpkin-util::Locale::from_str expects "af_za" or similar. + // WIT might generate "AfZa" or "af_za" depending on bindgen config. + // Let's assume standard bindgen which might produce "AfZa". + // We'll replace kebab-case if necessary. + let s = s.replace('-', "_"); + UtilLocale::from_str(&s).unwrap_or(UtilLocale::EnUs) +} diff --git a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1_0/mod.rs b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1_0/mod.rs index 6ec7a99d8..e15c3a57b 100644 --- a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1_0/mod.rs +++ b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1_0/mod.rs @@ -11,6 +11,7 @@ pub mod common; pub mod context; pub mod entity; pub mod events; +pub mod i18n; pub mod logging; pub mod permission; pub mod player;