feat(i18n): add seven UI locales

This commit is contained in:
Hakan Seven 2026-08-14 11:06:12 +03:00
commit 26fd9a3c02
23 changed files with 24729 additions and 31 deletions

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = إغلاق .close = إغلاق

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = Schließen .close = Schließen

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = Close .close = Close
@ -547,7 +554,7 @@ common =
.layer-state-name-cannot-be-empty = Layer state name cannot be empty. .layer-state-name-cannot-be-empty = Layer state name cannot be empty.
.layers = Layers .layers = Layers
.layout = Layout .layout = Layout
.layout-name-silindi = Layout "__ocs_fmt_0__" silindi .layout-name-silindi = Layout "__ocs_fmt_0__" deleted
.layout-new-name-created-use-mview-to-add-a-vie = Layout "__ocs_fmt_0__" created — use MVIEW to add a viewport .layout-new-name-created-use-mview-to-add-a-vie = Layout "__ocs_fmt_0__" created — use MVIEW to add a viewport
.layout-orig-new-name = Layout "__ocs_fmt_0__" → "__ocs_fmt_1__" .layout-orig-new-name = Layout "__ocs_fmt_0__" → "__ocs_fmt_1__"
.layout-name-created = Layout '__ocs_fmt_0__' created. .layout-name-created = Layout '__ocs_fmt_0__' created.

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = Cerrar .close = Cerrar

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = Fermer .close = Fermer

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = बंद करें .close = बंद करें

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = 閉じる .close = 閉じる

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = Sluiten .close = Sluiten

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = Fechar .close = Fechar

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = Замкнуть .close = Замкнуть

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = Kapat .close = Kapat

View file

@ -12,6 +12,13 @@ language =
.portuguese = Português (Brasil) .portuguese = Português (Brasil)
.arabic = العربية .arabic = العربية
.japanese = 日本語 .japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action = action =
.close = 关闭 .close = 关闭

File diff suppressed because it is too large Load diff

View file

@ -49,23 +49,44 @@ pub enum Language {
ArSa, ArSa,
#[serde(rename = "ja-JP")] #[serde(rename = "ja-JP")]
JaJp, JaJp,
#[serde(rename = "ko-KR")]
KoKr,
#[serde(rename = "cs-CZ")]
CsCz,
#[serde(rename = "it-IT")]
ItIt,
#[serde(rename = "fi-FI")]
FiFi,
#[serde(rename = "hu-HU")]
HuHu,
#[serde(rename = "pl-PL")]
PlPl,
#[serde(rename = "zh-TW")]
ZhTw,
} }
impl Language { impl Language {
pub const ALL: [Language; 13] = [ pub const ALL: [Language; 20] = [
Language::System, Language::System,
Language::EnUs, Language::EnUs,
Language::TrTr, Language::PtBr,
Language::CsCz,
Language::NlNl, Language::NlNl,
Language::FrFr, Language::FrFr,
Language::FiFi,
Language::DeDe, Language::DeDe,
Language::HiIn, Language::HuHu,
Language::ItIt,
Language::JaJp,
Language::KoKr,
Language::PlPl,
Language::RuRu, Language::RuRu,
Language::ZhCn, Language::ZhCn,
Language::EsEs, Language::EsEs,
Language::PtBr, Language::ZhTw,
Language::TrTr,
Language::HiIn,
Language::ArSa, Language::ArSa,
Language::JaJp,
]; ];
fn requested(self) -> Vec<i18n_embed::unic_langid::LanguageIdentifier> { fn requested(self) -> Vec<i18n_embed::unic_langid::LanguageIdentifier> {
@ -83,6 +104,13 @@ impl Language {
Language::PtBr => vec!["pt-BR".parse().expect("valid locale")], Language::PtBr => vec!["pt-BR".parse().expect("valid locale")],
Language::ArSa => vec!["ar-SA".parse().expect("valid locale")], Language::ArSa => vec!["ar-SA".parse().expect("valid locale")],
Language::JaJp => vec!["ja-JP".parse().expect("valid locale")], Language::JaJp => vec!["ja-JP".parse().expect("valid locale")],
Language::KoKr => vec!["ko-KR".parse().expect("valid locale")],
Language::CsCz => vec!["cs-CZ".parse().expect("valid locale")],
Language::ItIt => vec!["it-IT".parse().expect("valid locale")],
Language::FiFi => vec!["fi-FI".parse().expect("valid locale")],
Language::HuHu => vec!["hu-HU".parse().expect("valid locale")],
Language::PlPl => vec!["pl-PL".parse().expect("valid locale")],
Language::ZhTw => vec!["zh-TW".parse().expect("valid locale")],
} }
} }
@ -101,6 +129,13 @@ impl Language {
Language::PtBr => crate::tr!("language", "portuguese"), Language::PtBr => crate::tr!("language", "portuguese"),
Language::ArSa => crate::tr!("language", "arabic"), Language::ArSa => crate::tr!("language", "arabic"),
Language::JaJp => crate::tr!("language", "japanese"), Language::JaJp => crate::tr!("language", "japanese"),
Language::KoKr => crate::tr!("language", "korean"),
Language::CsCz => crate::tr!("language", "czech"),
Language::ItIt => crate::tr!("language", "italian"),
Language::FiFi => crate::tr!("language", "finnish"),
Language::HuHu => crate::tr!("language", "hungarian"),
Language::PlPl => crate::tr!("language", "polish"),
Language::ZhTw => crate::tr!("language", "chinese-traditional"),
} }
} }
} }

View file

@ -17,11 +17,12 @@ use std::sync::Arc;
/// A script we ship a Noto subset for. [`script_of`] maps a char to one. /// A script we ship a Noto subset for. [`script_of`] maps a char to one.
/// ///
/// CJK is split by language — Chinese, Japanese and Korean each get their own /// CJK is split by language — Simplified Chinese, Traditional Chinese,
/// file. Their ideographs (Han, U+4E009FFF) share the same code points but /// Japanese and Korean each get their own file. Their ideographs (Han,
/// differ in glyph shape, so the shared block is routed by the document's /// U+4E009FFF) share the same code points but differ in glyph shape, so the
/// language (see [`set_cjk_lang_from_codepage`]); kana is always Japanese and /// shared block is routed by the document's language (see
/// Hangul always Korean. /// [`set_cjk_lang_from_codepage`]); kana is always Japanese and Hangul always
/// Korean.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Script { pub enum Script {
Latin, Latin,
@ -32,6 +33,7 @@ pub enum Script {
Thai, Thai,
Devanagari, Devanagari,
Chinese, Chinese,
TraditionalChinese,
Japanese, Japanese,
Korean, Korean,
} }
@ -49,6 +51,7 @@ impl Script {
Script::Thai => "fonts/thai.ttf", Script::Thai => "fonts/thai.ttf",
Script::Devanagari => "fonts/devanagari.ttf", Script::Devanagari => "fonts/devanagari.ttf",
Script::Chinese => "fonts/chinese.ttf", Script::Chinese => "fonts/chinese.ttf",
Script::TraditionalChinese => "fonts/traditional_chinese.ttf",
Script::Japanese => "fonts/japanese.ttf", Script::Japanese => "fonts/japanese.ttf",
Script::Korean => "fonts/korean.ttf", Script::Korean => "fonts/korean.ttf",
} }
@ -57,6 +60,7 @@ impl Script {
pub fn family(self) -> &'static str { pub fn family(self) -> &'static str {
match self { match self {
Script::Chinese => "Noto Sans CJK SC", Script::Chinese => "Noto Sans CJK SC",
Script::TraditionalChinese => "Noto Sans CJK TC",
Script::Japanese => "Noto Sans CJK JP", Script::Japanese => "Noto Sans CJK JP",
Script::Korean => "Noto Sans CJK KR", Script::Korean => "Noto Sans CJK KR",
Script::Latin Script::Latin
@ -80,6 +84,7 @@ impl Script {
7 => Script::Chinese, 7 => Script::Chinese,
8 => Script::Japanese, 8 => Script::Japanese,
9 => Script::Korean, 9 => Script::Korean,
10 => Script::TraditionalChinese,
_ => Script::Latin, _ => Script::Latin,
} }
} }
@ -97,12 +102,13 @@ impl Script {
Script::Chinese => 7, Script::Chinese => 7,
Script::Japanese => 8, Script::Japanese => 8,
Script::Korean => 9, Script::Korean => 9,
Script::TraditionalChinese => 10,
} }
} }
} }
/// Language used to render shared Han ideographs: 0 = Chinese, 1 = Japanese, /// Language used to render shared Han ideographs: 0 = Simplified Chinese,
/// 2 = Korean. Set from the active document's code page. /// 1 = Japanese, 2 = Korean, 3 = Traditional Chinese.
static CJK_LANG: AtomicU8 = AtomicU8::new(0); static CJK_LANG: AtomicU8 = AtomicU8::new(0);
static PRIMARY_SCRIPT: AtomicU8 = AtomicU8::new(0); static PRIMARY_SCRIPT: AtomicU8 = AtomicU8::new(0);
static FONT_GENERATION: AtomicU64 = AtomicU64::new(0); static FONT_GENERATION: AtomicU64 = AtomicU64::new(0);
@ -117,22 +123,29 @@ fn bump_generation() {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
pub fn scripts_for_language_tag(language: &str) -> Vec<Script> { pub fn scripts_for_language_tag(language: &str) -> Vec<Script> {
let language = language let full_language = language.to_ascii_lowercase().replace('_', "-");
let language = full_language
.split(['-', '_']) .split(['-', '_'])
.next() .next()
.unwrap_or(language) .unwrap_or(&full_language)
.to_ascii_lowercase(); .to_ascii_lowercase();
let script = match language.as_str() { let script = if matches!(full_language.as_str(), "zh-tw" | "zh-hk")
"ar" | "fa" | "ur" => Some(Script::Arabic), || full_language.starts_with("zh-hant")
"el" => Some(Script::Greek), {
"he" | "yi" => Some(Script::Hebrew), Some(Script::TraditionalChinese)
"hi" | "mr" | "ne" => Some(Script::Devanagari), } else {
"ja" => Some(Script::Japanese), match language.as_str() {
"ko" => Some(Script::Korean), "ar" | "fa" | "ur" => Some(Script::Arabic),
"ru" | "uk" | "bg" | "sr" => Some(Script::Cyrillic), "el" => Some(Script::Greek),
"th" => Some(Script::Thai), "he" | "yi" => Some(Script::Hebrew),
"zh" => Some(Script::Chinese), "hi" | "mr" | "ne" => Some(Script::Devanagari),
_ => None, "ja" => Some(Script::Japanese),
"ko" => Some(Script::Korean),
"ru" | "uk" | "bg" | "sr" => Some(Script::Cyrillic),
"th" => Some(Script::Thai),
"zh" => Some(Script::Chinese),
_ => None,
}
}; };
vec![script.unwrap_or(Script::Latin)] vec![script.unwrap_or(Script::Latin)]
} }
@ -184,22 +197,24 @@ fn cjk_lang() -> Script {
match CJK_LANG.load(Ordering::Relaxed) { match CJK_LANG.load(Ordering::Relaxed) {
1 => Script::Japanese, 1 => Script::Japanese,
2 => Script::Korean, 2 => Script::Korean,
3 => Script::TraditionalChinese,
_ => Script::Chinese, _ => Script::Chinese,
} }
} }
/// Point the shared-Han routing at a language based on a DWG/DXF code page /// Point the shared-Han routing at a language based on a DWG/DXF code page
/// (`$DWGCODEPAGE`), e.g. `ANSI_932` → Japanese, `ANSI_949` → Korean, GB/936 or /// (`$DWGCODEPAGE`), e.g. `ANSI_932` → Japanese, `ANSI_949` → Korean and
/// anything else → Chinese. Returns `true` if the language changed (the caller /// `ANSI_950` → Traditional Chinese. Returns `true` if the language changed.
/// then clears the glyph cache and re-tessellates).
pub fn set_cjk_lang_from_codepage(code_page: &str) -> bool { pub fn set_cjk_lang_from_codepage(code_page: &str) -> bool {
let c = code_page.to_ascii_uppercase(); let c = code_page.to_ascii_uppercase();
let lang = if c.contains("932") || c.contains("SJIS") || c.contains("SHIFT") { let lang = if c.contains("932") || c.contains("SJIS") || c.contains("SHIFT") {
1 // Japanese (Shift-JIS) 1 // Japanese (Shift-JIS)
} else if c.contains("949") || c.contains("KOR") || c.contains("UHC") { } else if c.contains("949") || c.contains("KOR") || c.contains("UHC") {
2 // Korean 2 // Korean
} else if c.contains("950") || c.contains("BIG5") {
3 // Traditional Chinese
} else { } else {
0 // Chinese (936 / GB / 950 / Big5) or non-CJK default 0 // Simplified Chinese (936 / GB) or non-CJK default
}; };
CJK_LANG.swap(lang, Ordering::Relaxed) != lang CJK_LANG.swap(lang, Ordering::Relaxed) != lang
} }

View file

@ -49,7 +49,8 @@ merge /tmp/NotoDeva.ttf /tmp/NotoDevaMerged.ttf
sub /tmp/NotoDevaMerged.ttf "U+0000-024F,U+1E00-1EFF,U+2000-206F,U+0900-097F,U+A8E0-A8FF" devanagari.ttf sub /tmp/NotoDevaMerged.ttf "U+0000-024F,U+1E00-1EFF,U+2000-206F,U+0900-097F,U+A8E0-A8FF" devanagari.ttf
# CJK comes from the noto-cjk repo (CFF/OTF; ttf-parser reads CFF outlines) and # CJK comes from the noto-cjk repo (CFF/OTF; ttf-parser reads CFF outlines) and
# is split by language: Chinese, Japanese and Korean each get their own file. # is split by language: Simplified Chinese, Traditional Chinese, Japanese and
# Korean each get their own file.
# Han ideographs share code points but differ in glyph shape, so each language # Han ideographs share code points but differ in glyph shape, so each language
# ships its own. These are the heavy ones and remain split so startup only loads # ships its own. These are the heavy ones and remain split so startup only loads
# the active language. # the active language.
@ -58,6 +59,10 @@ dl /tmp/NotoSC.otf "$CJK/SimplifiedChinese/NotoSansCJKsc-Regular.otf"
sub /tmp/NotoSC.otf "U+3000-303F,U+4E00-9FFF,U+FF00-FFEF" /tmp/chinese.otf sub /tmp/NotoSC.otf "U+3000-303F,U+4E00-9FFF,U+FF00-FFEF" /tmp/chinese.otf
collection chinese.ttf latin.ttf /tmp/chinese.otf collection chinese.ttf latin.ttf /tmp/chinese.otf
dl /tmp/NotoTC.otf "$CJK/TraditionalChinese/NotoSansCJKtc-Regular.otf"
sub /tmp/NotoTC.otf "U+3000-303F,U+4E00-9FFF,U+FF00-FFEF" /tmp/traditional_chinese.otf
collection traditional_chinese.ttf latin.ttf /tmp/traditional_chinese.otf
dl /tmp/NotoJP.otf "$CJK/Japanese/NotoSansCJKjp-Regular.otf" dl /tmp/NotoJP.otf "$CJK/Japanese/NotoSansCJKjp-Regular.otf"
sub /tmp/NotoJP.otf "U+3000-303F,U+3040-30FF,U+31F0-31FF,U+4E00-9FFF,U+FF00-FFEF" /tmp/japanese.otf sub /tmp/NotoJP.otf "U+3000-303F,U+3040-30FF,U+31F0-31FF,U+4E00-9FFF,U+FF00-FFEF" /tmp/japanese.otf
collection japanese.ttf latin.ttf /tmp/japanese.otf collection japanese.ttf latin.ttf /tmp/japanese.otf

Binary file not shown.