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)
.arabic = العربية
.japanese = 日本語
.korean = 한국어
.czech = Čeština
.italian = Italiano
.finnish = Suomi
.hungarian = Magyar
.polish = Polski
.chinese-traditional = 繁體中文
action =
.close = إغلاق

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -49,23 +49,44 @@ pub enum Language {
ArSa,
#[serde(rename = "ja-JP")]
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 {
pub const ALL: [Language; 13] = [
pub const ALL: [Language; 20] = [
Language::System,
Language::EnUs,
Language::TrTr,
Language::PtBr,
Language::CsCz,
Language::NlNl,
Language::FrFr,
Language::FiFi,
Language::DeDe,
Language::HiIn,
Language::HuHu,
Language::ItIt,
Language::JaJp,
Language::KoKr,
Language::PlPl,
Language::RuRu,
Language::ZhCn,
Language::EsEs,
Language::PtBr,
Language::ZhTw,
Language::TrTr,
Language::HiIn,
Language::ArSa,
Language::JaJp,
];
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::ArSa => vec!["ar-SA".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::ArSa => crate::tr!("language", "arabic"),
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.
///
/// CJK is split by language — Chinese, Japanese and Korean each get their own
/// file. Their ideographs (Han, U+4E009FFF) share the same code points but
/// differ in glyph shape, so the shared block is routed by the document's
/// language (see [`set_cjk_lang_from_codepage`]); kana is always Japanese and
/// Hangul always Korean.
/// CJK is split by language — Simplified Chinese, Traditional Chinese,
/// Japanese and Korean each get their own file. Their ideographs (Han,
/// U+4E009FFF) share the same code points but differ in glyph shape, so the
/// shared block is routed by the document's language (see
/// [`set_cjk_lang_from_codepage`]); kana is always Japanese and Hangul always
/// Korean.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Script {
Latin,
@ -32,6 +33,7 @@ pub enum Script {
Thai,
Devanagari,
Chinese,
TraditionalChinese,
Japanese,
Korean,
}
@ -49,6 +51,7 @@ impl Script {
Script::Thai => "fonts/thai.ttf",
Script::Devanagari => "fonts/devanagari.ttf",
Script::Chinese => "fonts/chinese.ttf",
Script::TraditionalChinese => "fonts/traditional_chinese.ttf",
Script::Japanese => "fonts/japanese.ttf",
Script::Korean => "fonts/korean.ttf",
}
@ -57,6 +60,7 @@ impl Script {
pub fn family(self) -> &'static str {
match self {
Script::Chinese => "Noto Sans CJK SC",
Script::TraditionalChinese => "Noto Sans CJK TC",
Script::Japanese => "Noto Sans CJK JP",
Script::Korean => "Noto Sans CJK KR",
Script::Latin
@ -80,6 +84,7 @@ impl Script {
7 => Script::Chinese,
8 => Script::Japanese,
9 => Script::Korean,
10 => Script::TraditionalChinese,
_ => Script::Latin,
}
}
@ -97,12 +102,13 @@ impl Script {
Script::Chinese => 7,
Script::Japanese => 8,
Script::Korean => 9,
Script::TraditionalChinese => 10,
}
}
}
/// Language used to render shared Han ideographs: 0 = Chinese, 1 = Japanese,
/// 2 = Korean. Set from the active document's code page.
/// Language used to render shared Han ideographs: 0 = Simplified Chinese,
/// 1 = Japanese, 2 = Korean, 3 = Traditional Chinese.
static CJK_LANG: AtomicU8 = AtomicU8::new(0);
static PRIMARY_SCRIPT: AtomicU8 = AtomicU8::new(0);
static FONT_GENERATION: AtomicU64 = AtomicU64::new(0);
@ -117,12 +123,18 @@ fn bump_generation() {
#[cfg(target_arch = "wasm32")]
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(['-', '_'])
.next()
.unwrap_or(language)
.unwrap_or(&full_language)
.to_ascii_lowercase();
let script = match language.as_str() {
let script = if matches!(full_language.as_str(), "zh-tw" | "zh-hk")
|| full_language.starts_with("zh-hant")
{
Some(Script::TraditionalChinese)
} else {
match language.as_str() {
"ar" | "fa" | "ur" => Some(Script::Arabic),
"el" => Some(Script::Greek),
"he" | "yi" => Some(Script::Hebrew),
@ -133,6 +145,7 @@ pub fn scripts_for_language_tag(language: &str) -> Vec<Script> {
"th" => Some(Script::Thai),
"zh" => Some(Script::Chinese),
_ => None,
}
};
vec![script.unwrap_or(Script::Latin)]
}
@ -184,22 +197,24 @@ fn cjk_lang() -> Script {
match CJK_LANG.load(Ordering::Relaxed) {
1 => Script::Japanese,
2 => Script::Korean,
3 => Script::TraditionalChinese,
_ => Script::Chinese,
}
}
/// 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
/// anything else → Chinese. Returns `true` if the language changed (the caller
/// then clears the glyph cache and re-tessellates).
/// (`$DWGCODEPAGE`), e.g. `ANSI_932` → Japanese, `ANSI_949` → Korean and
/// `ANSI_950` → Traditional Chinese. Returns `true` if the language changed.
pub fn set_cjk_lang_from_codepage(code_page: &str) -> bool {
let c = code_page.to_ascii_uppercase();
let lang = if c.contains("932") || c.contains("SJIS") || c.contains("SHIFT") {
1 // Japanese (Shift-JIS)
} else if c.contains("949") || c.contains("KOR") || c.contains("UHC") {
2 // Korean
} else if c.contains("950") || c.contains("BIG5") {
3 // Traditional Chinese
} 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
}

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
# 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
# ships its own. These are the heavy ones and remain split so startup only loads
# 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
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"
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

Binary file not shown.