Merge pull request #813 from alrifatsabbir/bengali-ui-translation

Add Bengali UI Translation
This commit is contained in:
BFlat
2026-10-20 04:10:12 +07:00
committed by GitHub
5 changed files with 1775 additions and 10 deletions
+5
View File
@@ -37,6 +37,11 @@ real_name = "Justin John"
[people.Losminek]
[people.alrifatsabbir]
real_name = "Al Rifat Sabbir"
display_name = "Al Rifat Sabbir"
sync_github_name = true
[people.RevDonz]
[people.Nael-Nathanael]
File diff suppressed because it is too large Load Diff
+26 -7
View File
@@ -1,8 +1,9 @@
//! Chinese, Japanese and Korean text in the UI. egui's own fonts and Inter have no CJK glyphs, so
//! the UI adds a face per script it needs: the UI language's, the scripts in the open file's names
//! Chinese, Japanese, Korean and Bengali text in the UI. egui's own fonts and Inter have no glyphs
//! for them, so the UI adds a face per script it needs: the UI language's, the scripts in the open file's names
//! and comments, the language picker's and typed text. Desktop finds them among the installed
//! fonts (the system font scan), only once one is needed, so English users load none; the web
//! build has only the CJK faces built in from craft-fonts (`FIGCRAFT_EMBED_CJK`), else none.
//! build has only the CJK faces built in from craft-fonts (`FIGCRAFT_EMBED_CJK`), else none (no
//! Bengali face is built in, so the web leaves Bengali out).
use std::sync::Arc;
@@ -12,6 +13,13 @@ pub const KANA: u8 = 1;
pub const HANGUL: u8 = 2;
/// Han characters (and CJK punctuation and full-width forms).
pub const HAN: u8 = 4;
/// Bengali script.
pub const BENGALI: u8 = 8;
/// Every script bit: nothing more to look for once all have a face.
pub const ALL: u8 = KANA | HANGUL | HAN | BENGALI;
/// Bengali faces: cross-platform, Windows, macOS, then Linux names.
const BENGALI_FONTS: &[&str] = &["Noto Sans Bengali", "Nirmala UI", "Bangla Sangam MN", "Kalpurush", "SolaimanLipi"];
/// Japanese faces, the built-in one first: Windows, macOS, then Linux names.
const JAPANESE: &[&str] = &[
@@ -46,24 +54,26 @@ const CHINESE: &[&str] = &[
"Droid Sans Fallback",
];
/// The CJK scripts in `s`.
/// The CJK and Bengali scripts in `s`.
pub fn scripts(s: &str) -> u8 {
s.chars().fold(0, |m, c| {
m | match u32::from(c) {
0x3040..=0x30FF | 0x31F0..=0x31FF | 0xFF66..=0xFF9F => KANA,
0x1100..=0x11FF | 0x3130..=0x318F | 0xA960..=0xA97F | 0xAC00..=0xD7FF | 0xFFA0..=0xFFDC => HANGUL,
0x3000..=0x303F | 0x3400..=0x4DBF | 0x4E00..=0x9FFF | 0xF900..=0xFAFF | 0xFF01..=0xFF65 | 0x20000..=0x3FFFF => HAN,
0x0980..=0x09FF => BENGALI,
_ => 0,
}
})
}
/// The CJK scripts a UI language (a catalog code) is written in.
/// The scripts a UI language (a catalog code) is written in.
pub fn language(code: &str) -> u8 {
match code.split('-').next() {
Some("ja") => KANA | HAN,
Some("ko") => HANGUL,
Some("zh") => HAN,
Some("bn") => BENGALI,
_ => 0,
}
}
@@ -98,10 +108,16 @@ fn samples(need: u8, ui: u8) -> Vec<(char, Vec<&'static str>)> {
(false, HANGUL) => ('漢', [KOREAN, JAPANESE, CHINESE].concat()),
(false, _) => ('漢', [JAPANESE, KOREAN, CHINESE].concat()),
};
let mut v = vec![(KANA, ('あ', JAPANESE.to_vec())), (HAN, han), (HANGUL, ('한', KOREAN.to_vec()))];
let mut v = vec![(KANA, ('あ', JAPANESE.to_vec())), (HAN, han), (HANGUL, ('한', KOREAN.to_vec())), (BENGALI, ('অ', BENGALI_FONTS.to_vec()))];
match ui {
HANGUL => v.reverse(),
HAN => v.swap(0, 1),
BENGALI => {
if let Some(pos) = v.iter().position(|(bit, _)| *bit == BENGALI) {
let item = v.remove(pos);
v.insert(0, item);
}
}
_ => {}
}
v.into_iter().filter(|(bit, _)| need & bit != 0).map(|(_, s)| s).collect()
@@ -133,11 +149,13 @@ mod tests {
assert_eq!(scripts("ボタン"), KANA);
assert_eq!(scripts("버튼"), HANGUL);
assert_eq!(scripts("按钮"), HAN);
assert_eq!(scripts("বাংলা"), BENGALI);
assert_eq!(scripts("日本語のレイヤー(1)"), KANA | HAN);
assert_eq!(language("ja"), KANA | HAN);
assert_eq!(language("ko"), HANGUL);
assert_eq!(language("zh-Hant"), HAN);
assert_eq!(language("zh-Hans"), HAN);
assert_eq!(language("bn"), BENGALI);
assert_eq!(language("fr"), 0);
assert!(["en", "es", "es-419", "fr", "de", "pt-BR", "tr", "id"].iter().all(|c| can_show(c)));
}
@@ -156,6 +174,7 @@ mod tests {
let order = |need, ui| samples(need, ui).into_iter().map(|(c, _)| c).collect::<String>();
let first_face = |need, ui| samples(need, ui).first().and_then(|(_, f)| f.first()).copied();
assert_eq!(order(KANA | HAN | HANGUL, 0), "あ漢한");
assert_eq!(order(KANA | HAN | HANGUL | BENGALI, language("bn")), "অあ漢한");
assert_eq!(order(KANA | HAN | HANGUL, KANA | HAN), "あ漢한");
assert_eq!(order(KANA | HAN | HANGUL, HANGUL), "한漢あ");
assert_eq!(order(HANGUL, 0), "한");
@@ -168,6 +187,6 @@ mod tests {
assert_eq!(order(KANA | HAN, language("zh-Hans")), "们あ");
assert!(["Microsoft YaHei UI", "PingFang SC", "Noto Sans CJK SC"].iter().all(|f| samples(HAN, HAN)[0].1[..4].contains(f)));
assert!(faces(0, "en", &|_| false).is_empty());
assert!(faces(KANA | HANGUL | HAN, "ja", &|_| true).is_empty(), "nothing is looked up for scripts the UI draws");
assert!(faces(KANA | HANGUL | HAN | BENGALI, "ja", &|_| true).is_empty(), "nothing is looked up for scripts the UI draws");
}
}
+2 -2
View File
@@ -1307,11 +1307,11 @@ impl FigApp {
self.session.prefs.reduce_motion || self.services.reduce_motion()
}
/// The CJK scripts the UI shows: the language's, the language picker's (Preferences open),
/// The CJK and Bengali scripts the UI shows: the language's, the language picker's (Preferences open),
/// typed text's, and those in the open file's names and comments (read when it changes, not
/// mid-drag). Nothing is checked once every script has a face.
fn cjk_needed(&mut self, ctx: &egui::Context, installed: u8) -> u8 {
if installed == cjk::KANA | cjk::HANGUL | cjk::HAN {
if installed == cjk::ALL {
return installed;
}
let mut need = i18n::current().map_or(0, |l| cjk::language(l.code));
+1 -1
View File
@@ -17,7 +17,7 @@ Simplified.
The catalogs: English (`en`, the source), and Spanish (`es`, with the Latin American overlay
`es-419`), French (`fr`), German (`de`), Dutch (`nl`), Brazilian Portuguese (`pt-BR`), Japanese
(`ja`), Korean (`ko`), Simplified Chinese (`zh-Hans`), Czech (`cs`), Indonesian (`id`), Finnish
(`fi`), Polish (`pl`) and Georgian (`ka`), machine-drafted and waiting for native speakers' review. Russian (`ru`, Русский) was
(`fi`), Polish (`pl`), Georgian (`ka`) and Bengali (`bn`), machine-drafted and waiting for native speakers' review. Russian (`ru`, Русский) was
reviewed and approved by VanTan; its catalog keeps Frame, Dev Mode and Smart animate as familiar
tool names and uses « » quotes. Turkish (`tr`) was machine-drafted and reviewed by a native speaker,
and Swedish (`sv`) translates every UI string, command label and menu wording.