use crate::language::Language;
use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::os::raw::c_char;
use wxdragon_sys as ffi;
pub struct Translations {
ptr: *mut ffi::wxd_Translations_t,
owned: bool,
_marker: PhantomData<*const ()>,
}
impl Translations {
pub fn get() -> Option<Self> {
let ptr = unsafe { ffi::wxd_Translations_Get() };
if ptr.is_null() {
None
} else {
Some(Self {
ptr,
owned: false,
_marker: PhantomData,
})
}
}
pub fn new() -> Self {
let ptr = unsafe { ffi::wxd_Translations_Create() };
Self {
ptr,
owned: true,
_marker: PhantomData,
}
}
pub fn set_global(mut self) {
if !self.ptr.is_null() {
unsafe { ffi::wxd_Translations_Set(self.ptr) };
self.owned = false;
}
}
pub fn set_language(&self, lang: Language) {
if self.ptr.is_null() {
return;
}
unsafe { ffi::wxd_Translations_SetLanguage(self.ptr, lang.as_i32()) };
}
pub fn set_language_str(&self, lang: &str) {
if self.ptr.is_null() {
return;
}
let c_lang = match CString::new(lang) {
Ok(s) => s,
Err(_) => return,
};
unsafe { ffi::wxd_Translations_SetLanguageStr(self.ptr, c_lang.as_ptr()) };
}
pub fn add_catalog(&self, domain: &str) -> bool {
self.add_catalog_with_lang(domain, Language::English)
}
pub fn add_catalog_with_lang(&self, domain: &str, msg_id_language: Language) -> bool {
if self.ptr.is_null() {
return false;
}
let c_domain = match CString::new(domain) {
Ok(s) => s,
Err(_) => return false,
};
unsafe { ffi::wxd_Translations_AddCatalog(self.ptr, c_domain.as_ptr(), msg_id_language.as_i32()) }
}
pub fn add_std_catalog(&self) -> bool {
if self.ptr.is_null() {
return false;
}
unsafe { ffi::wxd_Translations_AddStdCatalog(self.ptr) }
}
pub fn is_loaded(&self, domain: &str) -> bool {
if self.ptr.is_null() {
return false;
}
let c_domain = match CString::new(domain) {
Ok(s) => s,
Err(_) => return false,
};
unsafe { ffi::wxd_Translations_IsLoaded(self.ptr, c_domain.as_ptr()) }
}
pub fn get_string(&self, orig: &str, domain: &str) -> Option<String> {
if self.ptr.is_null() {
return None;
}
let c_orig = CString::new(orig).ok()?;
let c_domain = CString::new(domain).ok()?;
let len = unsafe {
ffi::wxd_Translations_GetTranslatedString(self.ptr, c_orig.as_ptr(), c_domain.as_ptr(), std::ptr::null_mut(), 0)
};
if len < 0 {
return None;
}
let mut buf: Vec<c_char> = vec![0; len as usize + 1];
unsafe {
ffi::wxd_Translations_GetTranslatedString(self.ptr, c_orig.as_ptr(), c_domain.as_ptr(), buf.as_mut_ptr(), buf.len())
};
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string() })
}
pub fn get_plural_string(&self, singular: &str, plural: &str, n: u32, domain: &str) -> Option<String> {
if self.ptr.is_null() {
return None;
}
let c_singular = CString::new(singular).ok()?;
let c_plural = CString::new(plural).ok()?;
let c_domain = CString::new(domain).ok()?;
let len = unsafe {
ffi::wxd_Translations_GetTranslatedPluralString(
self.ptr,
c_singular.as_ptr(),
c_plural.as_ptr(),
n,
c_domain.as_ptr(),
std::ptr::null_mut(),
0,
)
};
if len < 0 {
return None;
}
let mut buf: Vec<c_char> = vec![0; len as usize + 1];
unsafe {
ffi::wxd_Translations_GetTranslatedPluralString(
self.ptr,
c_singular.as_ptr(),
c_plural.as_ptr(),
n,
c_domain.as_ptr(),
buf.as_mut_ptr(),
buf.len(),
)
};
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string() })
}
pub fn get_header_value(&self, header: &str, domain: &str) -> Option<String> {
if self.ptr.is_null() {
return None;
}
let c_header = CString::new(header).ok()?;
let c_domain = CString::new(domain).ok()?;
let len = unsafe {
ffi::wxd_Translations_GetHeaderValue(self.ptr, c_header.as_ptr(), c_domain.as_ptr(), std::ptr::null_mut(), 0)
};
if len < 0 {
return None;
}
let mut buf: Vec<c_char> = vec![0; len as usize + 1];
unsafe {
ffi::wxd_Translations_GetHeaderValue(self.ptr, c_header.as_ptr(), c_domain.as_ptr(), buf.as_mut_ptr(), buf.len())
};
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string() })
}
pub fn get_best_translation(&self, domain: &str) -> Option<String> {
self.get_best_translation_with_lang(domain, Language::English)
}
pub fn get_best_translation_with_lang(&self, domain: &str, msg_id_language: Language) -> Option<String> {
if self.ptr.is_null() {
return None;
}
let c_domain = CString::new(domain).ok()?;
let len = unsafe {
ffi::wxd_Translations_GetBestTranslation(
self.ptr,
c_domain.as_ptr(),
msg_id_language.as_i32(),
std::ptr::null_mut(),
0,
)
};
if len < 0 {
return None;
}
let mut buf: Vec<c_char> = vec![0; len as usize + 1];
unsafe {
ffi::wxd_Translations_GetBestTranslation(
self.ptr,
c_domain.as_ptr(),
msg_id_language.as_i32(),
buf.as_mut_ptr(),
buf.len(),
)
};
Some(unsafe { CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string() })
}
pub fn get_available_translations(&self, domain: &str) -> Vec<String> {
if self.ptr.is_null() {
return Vec::new();
}
let c_domain = match CString::new(domain) {
Ok(s) => s,
Err(_) => return Vec::new(),
};
let count =
unsafe { ffi::wxd_Translations_GetAvailableTranslations(self.ptr, c_domain.as_ptr(), std::ptr::null_mut(), 0, 0) };
if count <= 0 {
return Vec::new();
}
let string_buf_len: usize = 32; let mut buffers: Vec<Vec<c_char>> = (0..count).map(|_| vec![0 as c_char; string_buf_len]).collect();
let mut ptrs: Vec<*mut c_char> = buffers.iter_mut().map(|b| b.as_mut_ptr()).collect();
unsafe {
ffi::wxd_Translations_GetAvailableTranslations(
self.ptr,
c_domain.as_ptr(),
ptrs.as_mut_ptr(),
count as usize,
string_buf_len,
)
};
buffers
.iter()
.filter_map(|buf| {
let cstr = unsafe { CStr::from_ptr(buf.as_ptr()) };
let s = cstr.to_string_lossy().to_string();
if s.is_empty() { None } else { Some(s) }
})
.collect()
}
}
impl Default for Translations {
fn default() -> Self {
Self::new()
}
}
impl Drop for Translations {
fn drop(&mut self) {
if self.owned && !self.ptr.is_null() {
unsafe { ffi::wxd_Translations_Destroy(self.ptr) };
}
}
}
pub fn add_catalog_lookup_path_prefix(prefix: &str) {
let c_prefix = match CString::new(prefix) {
Ok(s) => s,
Err(_) => return,
};
unsafe { ffi::wxd_FileTranslationsLoader_AddCatalogLookupPathPrefix(c_prefix.as_ptr()) };
}
pub fn translate(s: &str) -> String {
if let Some(translations) = Translations::get()
&& let Some(translated) = translations.get_string(s, "")
{
return translated;
}
s.to_string()
}
pub fn translate_plural(singular: &str, plural: &str, n: u32) -> String {
if let Some(translations) = Translations::get()
&& let Some(translated) = translations.get_plural_string(singular, plural, n, "")
{
return translated;
}
if n == 1 { singular.to_string() } else { plural.to_string() }
}
#[derive(Clone, Copy)]
pub struct LanguageInfo {
ptr: *const ffi::wxd_LanguageInfo_t,
}
impl LanguageInfo {
pub fn description(&self) -> String {
if self.ptr.is_null() {
return String::new();
}
let len = unsafe { ffi::wxd_LanguageInfo_GetDescription(self.ptr, std::ptr::null_mut(), 0) };
if len < 0 {
return String::new();
}
let mut buf = vec![0u8; len as usize + 1];
unsafe {
ffi::wxd_LanguageInfo_GetDescription(self.ptr, buf.as_mut_ptr() as *mut _, buf.len());
}
if let Some(last) = buf.last()
&& *last == 0
{
buf.pop();
}
String::from_utf8_lossy(&buf).to_string()
}
pub fn canonical_name(&self) -> String {
if self.ptr.is_null() {
return String::new();
}
let len = unsafe { ffi::wxd_LanguageInfo_GetCanonicalName(self.ptr, std::ptr::null_mut(), 0) };
if len < 0 {
return String::new();
}
let mut buf = vec![0u8; len as usize + 1];
unsafe {
ffi::wxd_LanguageInfo_GetCanonicalName(self.ptr, buf.as_mut_ptr() as *mut _, buf.len());
}
if let Some(last) = buf.last()
&& *last == 0
{
buf.pop();
}
String::from_utf8_lossy(&buf).to_string()
}
pub fn native_description(&self) -> String {
if self.ptr.is_null() {
return String::new();
}
let len = unsafe { ffi::wxd_LanguageInfo_GetDescriptionNative(self.ptr, std::ptr::null_mut(), 0) };
if len < 0 {
return String::new();
}
let mut buf = vec![0u8; len as usize + 1];
unsafe {
ffi::wxd_LanguageInfo_GetDescriptionNative(self.ptr, buf.as_mut_ptr() as *mut _, buf.len());
}
if let Some(last) = buf.last()
&& *last == 0
{
buf.pop();
}
String::from_utf8_lossy(&buf).to_string()
}
}
pub struct Locale;
impl Locale {
pub fn get_language_name(lang: Language) -> Option<String> {
let len = unsafe { ffi::wxd_Locale_GetLanguageName(lang.as_i32(), std::ptr::null_mut(), 0) };
if len < 0 {
return None;
}
let mut buf = vec![0u8; len as usize + 1];
unsafe {
ffi::wxd_Locale_GetLanguageName(lang.as_i32(), buf.as_mut_ptr() as *mut _, buf.len());
}
if let Some(last) = buf.last()
&& *last == 0
{
buf.pop();
}
Some(String::from_utf8_lossy(&buf).to_string())
}
pub fn get_language_canonical_name(lang: Language) -> Option<String> {
let len = unsafe { ffi::wxd_Locale_GetLanguageCanonicalName(lang.as_i32(), std::ptr::null_mut(), 0) };
if len < 0 {
return None;
}
let mut buf = vec![0u8; len as usize + 1];
unsafe {
ffi::wxd_Locale_GetLanguageCanonicalName(lang.as_i32(), buf.as_mut_ptr() as *mut _, buf.len());
}
if let Some(last) = buf.last()
&& *last == 0
{
buf.pop();
}
Some(String::from_utf8_lossy(&buf).to_string())
}
pub fn find_language_info(locale: &str) -> Option<LanguageInfo> {
let c_locale = CString::new(locale).ok()?;
let ptr = unsafe { ffi::wxd_Locale_FindLanguageInfo(c_locale.as_ptr()) };
if ptr.is_null() { None } else { Some(LanguageInfo { ptr }) }
}
pub fn get_language_info(lang: Language) -> Option<LanguageInfo> {
let ptr = unsafe { ffi::wxd_Locale_GetLanguageInfo(lang.as_i32()) };
if ptr.is_null() { None } else { Some(LanguageInfo { ptr }) }
}
pub fn get_system_language() -> Language {
let lang_id = unsafe { ffi::wxd_Locale_GetSystemLanguage() };
Language::from_i32(lang_id).unwrap_or(Language::Unknown)
}
}
pub struct UILocale {
ptr: *mut ffi::wxd_UILocale_t,
}
impl UILocale {
pub fn get_current() -> Self {
let ptr = unsafe { ffi::wxd_UILocale_GetCurrent() };
Self { ptr }
}
pub fn get_name(&self) -> String {
if self.ptr.is_null() {
return String::new();
}
let len = unsafe { ffi::wxd_UILocale_GetName(self.ptr, std::ptr::null_mut(), 0) };
if len < 0 {
return String::new();
}
let mut buf = vec![0u8; len as usize + 1];
unsafe {
ffi::wxd_UILocale_GetName(self.ptr, buf.as_mut_ptr() as *mut _, buf.len());
}
if let Some(last) = buf.last()
&& *last == 0
{
buf.pop();
}
String::from_utf8_lossy(&buf).to_string()
}
pub fn get_info(&self) -> Option<LanguageInfo> {
if self.ptr.is_null() {
return None;
}
let lang_id = unsafe { ffi::wxd_UILocale_GetLanguage(self.ptr) };
Locale::get_language_info(Language::from_i32(lang_id).unwrap_or(Language::Unknown))
}
}
impl Drop for UILocale {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { ffi::wxd_UILocale_Destroy(self.ptr) };
}
}
}