Skip to content

Commit 7c02a8e

Browse files
authored
update: 2.5
完善多语言支持
1 parent 08cc018 commit 7c02a8e

11 files changed

Lines changed: 327 additions & 27 deletions

app/index.html

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<meta name="robots" content="index, follow">
1111
<link rel="canonical" href="https://subs.js.org/ass-subset/">
1212
<link rel="alternate" hreflang="en" href="https://subs.js.org/ass-subset/">
13-
<link rel="alternate" hreflang="zh-CN" href="https://subs.js.org/ass-subset/?lang=zh">
13+
<link rel="alternate" hreflang="zh-CN" href="https://subs.js.org/ass-subset/?lang=zh-CN">
1414
<link rel="alternate" hreflang="zh-TW" href="https://subs.js.org/ass-subset/?lang=zh-TW">
1515
<link rel="alternate" hreflang="ja" href="https://subs.js.org/ass-subset/?lang=ja">
1616
<link rel="alternate" hreflang="ko" href="https://subs.js.org/ass-subset/?lang=ko">
@@ -21,7 +21,7 @@
2121
<link rel="alternate" hreflang="ar" href="https://subs.js.org/ass-subset/?lang=ar">
2222
<link rel="alternate" hreflang="x-default" href="https://subs.js.org/ass-subset/">
2323
<link rel="icon" type="image/jpeg" href="icons/icon-256.png">
24-
<meta name="version" content="2.4.19">
24+
<meta name="version" content="2.5">
2525
<meta property="og:type" content="website">
2626
<meta property="og:title" content="ASS Subsetter· MontageSubs">
2727
<meta property="og:description" content="Optimize ASS/SSA subtitle files with intelligent font subsetting and drawing command compression. Embed fonts with zero file bloat. Browser-based, free, open-source.">
@@ -1342,7 +1342,7 @@ <h1 class="brand-title" data-i18n="app.title">ASS Subsetter</h1>
13421342
aria-label="Switch language" aria-haspopup="menu" aria-expanded="false">A/文</button>
13431343
<div class="lang-menu" id="lang-menu" role="menu">
13441344
<button onclick="setLang('ar')" id="lang-ar" role="menuitem">Arabic · العربية</button>
1345-
<button onclick="setLang('zh')" id="lang-zh" class="active" role="menuitem">Chinese Simplified · 简体中文</button>
1345+
<button onclick="setLang('zh-CN')" id="lang-zh-CN" class="active" role="menuitem">Chinese Simplified · 简体中文</button>
13461346
<button onclick="setLang('zh-TW')" id="lang-zh-TW" role="menuitem">Chinese Traditional · 繁體中文</button>
13471347
<button onclick="setLang('en')" id="lang-en" role="menuitem">English</button>
13481348
<button onclick="setLang('ja')" id="lang-ja" role="menuitem">Japanese · 日本語</button>
@@ -1547,7 +1547,7 @@ <h3 id="preview-title" data-i18n="preview.title">Font Preview / Download</h3>
15471547
'use strict';
15481548

15491549
const I18N = {
1550-
zh: {
1550+
'zh-CN': {
15511551
'analysis.draw.label': '绘图指令(\\p1)',
15521552
'analysis.draw.none': '未发现绘图指令',
15531553
'analysis.draw.status.existing': '已子集化 {count} 个形状,当前无新绘图',
@@ -2871,28 +2871,46 @@ <h3 id="preview-title" data-i18n="preview.title">Font Preview / Download</h3>
28712871

28722872
function normFont(name) { return name.replace(/^@/, '').trim(); }
28732873

2874-
let currentLang = 'zh';
2874+
let currentLang = 'en';
28752875
(function () {
2876+
function normalizeLang(raw) {
2877+
const s = (raw || '').toLowerCase().trim();
2878+
if (!s) return null;
2879+
if (s.startsWith('zh-tw')) return 'zh-TW';
2880+
if (s.startsWith('zh-hk') || s.startsWith('zh-mo')) return 'zh-TW';
2881+
if (s.startsWith('zh')) return 'zh-CN';
2882+
if (s.startsWith('en')) return 'en';
2883+
if (s.startsWith('ja')) return 'ja';
2884+
if (s.startsWith('ko')) return 'ko';
2885+
if (s.startsWith('ar')) return 'ar';
2886+
if (s.startsWith('ru')) return 'ru';
2887+
if (s.startsWith('tr')) return 'tr';
2888+
if (s.startsWith('pt')) return 'pt-BR';
2889+
if (s.startsWith('es')) return 'es';
2890+
return null;
2891+
}
2892+
const VALID = {'ar':1,'zh-CN':1,'zh-TW':1,'en':1,'ja':1,'ko':1,'pt-BR':1,'ru':1,'es':1,'tr':1};
2893+
try {
2894+
const urlLang = new URLSearchParams(window.location.search).get('lang');
2895+
if (urlLang) {
2896+
const norm = normalizeLang(urlLang);
2897+
if (norm && VALID[norm]) {
2898+
currentLang = norm;
2899+
try { localStorage.setItem('ass-subset-lang', norm); } catch(_) {}
2900+
return;
2901+
}
2902+
}
2903+
} catch(_) {}
28762904
try {
28772905
const saved = localStorage.getItem('ass-subset-lang');
2878-
if (saved && I18N[saved]) { currentLang = saved; return; }
2906+
if (saved && VALID[saved]) { currentLang = saved; return; }
28792907
} catch (_) { }
28802908
const nav = (navigator.language || '').toLowerCase();
2881-
if (nav.startsWith('zh-tw') || nav.startsWith('zh-hk') || nav.startsWith('zh-mo')) currentLang = 'zh-TW';
2882-
else if (nav.startsWith('zh')) currentLang = 'zh';
2883-
else if (nav.startsWith('en')) currentLang = 'en';
2884-
else if (nav.startsWith('ja')) currentLang = 'ja';
2885-
else if (nav.startsWith('ko')) currentLang = 'ko';
2886-
else if (nav.startsWith('ar')) currentLang = 'ar';
2887-
else if (nav.startsWith('ru')) currentLang = 'ru';
2888-
else if (nav.startsWith('tr')) currentLang = 'tr';
2889-
else if (nav.startsWith('pt')) currentLang = 'pt-BR';
2890-
else if (nav.startsWith('es')) currentLang = 'es';
2891-
else currentLang = 'en';
2909+
currentLang = normalizeLang(nav) || 'en';
28922910
})();
28932911

28942912
function t(key, params) {
2895-
let str = (I18N[currentLang] && I18N[currentLang][key]) || I18N.zh[key] || key;
2913+
let str = (I18N[currentLang] && I18N[currentLang][key]) || I18N.en[key] || key;
28962914
if (params) {
28972915
for (const [k, v] of Object.entries(params)) str = str.replace(new RegExp('\\{' + k + '\\}', 'g'), v);
28982916
}
@@ -2913,9 +2931,9 @@ <h3 id="preview-title" data-i18n="preview.title">Font Preview / Download</h3>
29132931
el.setAttribute('aria-label', t(el.getAttribute('data-i18n-aria')));
29142932
});
29152933

2916-
const langAttrMap = { zh: 'zh-CN', 'zh-TW': 'zh-TW', en: 'en-US', ja: 'ja', ko: 'ko', ar: 'ar', ru: 'ru', tr: 'tr', 'pt-BR': 'pt-BR', es: 'es-419' };
2934+
const langAttrMap = { 'zh-CN': 'zh-CN', 'zh-TW': 'zh-TW', en: 'en', ja: 'ja', ko: 'ko', ar: 'ar', ru: 'ru', tr: 'tr', 'pt-BR': 'pt-BR', es: 'es' };
29172935
document.documentElement.lang = langAttrMap[currentLang] || currentLang;
2918-
['zh', 'zh-TW', 'en', 'ja', 'ko', 'ar', 'pt-BR', 'ru', 'es', 'tr'].forEach(l => {
2936+
['zh-CN', 'zh-TW', 'en', 'ja', 'ko', 'ar', 'pt-BR', 'ru', 'es', 'tr'].forEach(l => {
29192937
document.getElementById('lang-' + l)?.classList.toggle('active', currentLang === l);
29202938
});
29212939

@@ -2926,7 +2944,10 @@ <h3 id="preview-title" data-i18n="preview.title">Font Preview / Download</h3>
29262944
document.querySelector('meta[property="og:title"]')?.setAttribute('content', title);
29272945
document.querySelector('meta[property="og:description"]')?.setAttribute('content', t('app.subtitle'));
29282946
const manifest = document.getElementById('pwa-manifest');
2929-
if (manifest) manifest.setAttribute('href', currentLang === 'zh' ? 'manifest.json' : 'manifest-en.json');
2947+
if (manifest) {
2948+
const mLangs = {'zh-CN':'manifest-zh-CN.json','zh-TW':'manifest-zh-TW.json','ja':'manifest-ja.json','ko':'manifest-ko.json','es':'manifest-es.json','pt-BR':'manifest-pt-BR.json','ru':'manifest-ru.json','ar':'manifest-ar.json','tr':'manifest-tr.json'};
2949+
manifest.setAttribute('href', mLangs[currentLang] || 'manifest.json');
2950+
}
29302951

29312952
const v = document.querySelector('meta[name="version"]');
29322953
const verEl = document.getElementById('ver');
@@ -4712,8 +4733,8 @@ <h3 id="preview-title" data-i18n="preview.title">Font Preview / Download</h3>
47124733
script.setAttribute('data-reactions-enabled', '0');
47134734
script.setAttribute('data-emit-metadata', '0');
47144735
script.setAttribute('data-theme', theme);
4715-
const langMap = { 'ar': 'ar', 'zh': 'zh-CN', 'zh-TW': 'zh-TW', 'en': 'en', 'ja': 'ja', 'ko': 'ko', 'pt-BR': 'pt-BR', 'ru': 'ru', 'es': 'es', 'tr': 'tr' };
4716-
script.setAttribute('data-lang', langMap[currentLang] || 'zh-CN');
4736+
const langMap = { 'ar': 'ar', 'zh-CN': 'zh-CN', 'zh-TW': 'zh-TW', 'en': 'en', 'ja': 'ja', 'ko': 'ko', 'pt-BR': 'pt-BR', 'ru': 'ru', 'es': 'es', 'tr': 'tr' };
4737+
script.setAttribute('data-lang', langMap[currentLang] || 'en');
47174738
script.crossOrigin = 'anonymous';
47184739
script.async = true;
47194740
script.onload = () => { const el = document.getElementById('discuss-loading'); if (el) el.remove(); };

app/manifest-ar.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "أداة تحديد مجموعة فرعية ASS",
3+
"short_name": "ASS Subset",
4+
"description": "أداة عبر الإنترنت لتحديد مجموعات فرعية من الخطوط لترجمات ASS/SSA. تدعم تحديد مجموعات الرسم وتضمين الخطوط، وتعمل محليًا في المتصفح.",
5+
"start_url": "/ass-subset/",
6+
"scope": "/ass-subset/",
7+
"display": "standalone",
8+
"background_color": "#f6f5f2",
9+
"theme_color": "#c0392b",
10+
"lang": "ar",
11+
"icons": [
12+
{
13+
"src": "icons/icon-192.png",
14+
"sizes": "192x192",
15+
"type": "image/png",
16+
"purpose": "any"
17+
},
18+
{
19+
"src": "icons/icon-512.png",
20+
"sizes": "512x512",
21+
"type": "image/png",
22+
"purpose": "any"
23+
},
24+
{
25+
"src": "icons/icon-512.png",
26+
"sizes": "512x512",
27+
"type": "image/png",
28+
"purpose": "maskable"
29+
}
30+
]
31+
}

app/manifest-es.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "Herramienta ASS Subsetter",
3+
"short_name": "ASS Subset",
4+
"description": "Herramienta en línea de subconjunto de fuentes para subtítulos ASS/SSA. Admite subconjunto de dibujos e incrustación de fuentes, procesado localmente en el navegador.",
5+
"start_url": "/ass-subset/",
6+
"scope": "/ass-subset/",
7+
"display": "standalone",
8+
"background_color": "#f6f5f2",
9+
"theme_color": "#c0392b",
10+
"lang": "es",
11+
"icons": [
12+
{
13+
"src": "icons/icon-192.png",
14+
"sizes": "192x192",
15+
"type": "image/png",
16+
"purpose": "any"
17+
},
18+
{
19+
"src": "icons/icon-512.png",
20+
"sizes": "512x512",
21+
"type": "image/png",
22+
"purpose": "any"
23+
},
24+
{
25+
"src": "icons/icon-512.png",
26+
"sizes": "512x512",
27+
"type": "image/png",
28+
"purpose": "maskable"
29+
}
30+
]
31+
}

app/manifest-ja.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "ASS サブセットツール",
3+
"short_name": "ASSサブセット",
4+
"description": "ASS/SSA 字幕用のオンラインフォントサブセットツール。描画サブセット化とフォント埋め込みをブラウザ上でローカル処理します。",
5+
"start_url": "/ass-subset/",
6+
"scope": "/ass-subset/",
7+
"display": "standalone",
8+
"background_color": "#f6f5f2",
9+
"theme_color": "#c0392b",
10+
"lang": "ja",
11+
"icons": [
12+
{
13+
"src": "icons/icon-192.png",
14+
"sizes": "192x192",
15+
"type": "image/png",
16+
"purpose": "any"
17+
},
18+
{
19+
"src": "icons/icon-512.png",
20+
"sizes": "512x512",
21+
"type": "image/png",
22+
"purpose": "any"
23+
},
24+
{
25+
"src": "icons/icon-512.png",
26+
"sizes": "512x512",
27+
"type": "image/png",
28+
"purpose": "maskable"
29+
}
30+
]
31+
}

app/manifest-ko.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "ASS 서브셋 도구",
3+
"short_name": "ASS서브셋",
4+
"description": "ASS/SSA 자막용 온라인 폰트 서브셋 도구. 드로잉 서브셋화 및 폰트 임베딩을 브라우저에서 로컬로 처리합니다.",
5+
"start_url": "/ass-subset/",
6+
"scope": "/ass-subset/",
7+
"display": "standalone",
8+
"background_color": "#f6f5f2",
9+
"theme_color": "#c0392b",
10+
"lang": "ko",
11+
"icons": [
12+
{
13+
"src": "icons/icon-192.png",
14+
"sizes": "192x192",
15+
"type": "image/png",
16+
"purpose": "any"
17+
},
18+
{
19+
"src": "icons/icon-512.png",
20+
"sizes": "512x512",
21+
"type": "image/png",
22+
"purpose": "any"
23+
},
24+
{
25+
"src": "icons/icon-512.png",
26+
"sizes": "512x512",
27+
"type": "image/png",
28+
"purpose": "maskable"
29+
}
30+
]
31+
}

app/manifest-pt-BR.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "Ferramenta ASS Subsetter",
3+
"short_name": "ASS Subset",
4+
"description": "Ferramenta online de subconjunto de fontes para legendas ASS/SSA. Suporta subconjunto de desenho e incorporação de fontes, processado localmente no navegador.",
5+
"start_url": "/ass-subset/",
6+
"scope": "/ass-subset/",
7+
"display": "standalone",
8+
"background_color": "#f6f5f2",
9+
"theme_color": "#c0392b",
10+
"lang": "pt-BR",
11+
"icons": [
12+
{
13+
"src": "icons/icon-192.png",
14+
"sizes": "192x192",
15+
"type": "image/png",
16+
"purpose": "any"
17+
},
18+
{
19+
"src": "icons/icon-512.png",
20+
"sizes": "512x512",
21+
"type": "image/png",
22+
"purpose": "any"
23+
},
24+
{
25+
"src": "icons/icon-512.png",
26+
"sizes": "512x512",
27+
"type": "image/png",
28+
"purpose": "maskable"
29+
}
30+
]
31+
}

app/manifest-ru.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "ASS Сабсеттер",
3+
"short_name": "ASS Subset",
4+
"description": "Онлайн-инструмент для создания поднаборов шрифтов для субтитров ASS/SSA. Поддерживает поднабор рисунков и встраивание шрифтов, обрабатывается локально в браузере.",
5+
"start_url": "/ass-subset/",
6+
"scope": "/ass-subset/",
7+
"display": "standalone",
8+
"background_color": "#f6f5f2",
9+
"theme_color": "#c0392b",
10+
"lang": "ru",
11+
"icons": [
12+
{
13+
"src": "icons/icon-192.png",
14+
"sizes": "192x192",
15+
"type": "image/png",
16+
"purpose": "any"
17+
},
18+
{
19+
"src": "icons/icon-512.png",
20+
"sizes": "512x512",
21+
"type": "image/png",
22+
"purpose": "any"
23+
},
24+
{
25+
"src": "icons/icon-512.png",
26+
"sizes": "512x512",
27+
"type": "image/png",
28+
"purpose": "maskable"
29+
}
30+
]
31+
}

app/manifest-tr.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "ASS Alt Küme Aracı",
3+
"short_name": "ASS Subset",
4+
"description": "ASS/SSA altyazılar için çevrimiçi yazı tipi alt küme aracı. Çizim alt kümeleme ve yazı tipi gömmeyi destekler, tarayıcınızda yerel olarak işlenir.",
5+
"start_url": "/ass-subset/",
6+
"scope": "/ass-subset/",
7+
"display": "standalone",
8+
"background_color": "#f6f5f2",
9+
"theme_color": "#c0392b",
10+
"lang": "tr",
11+
"icons": [
12+
{
13+
"src": "icons/icon-192.png",
14+
"sizes": "192x192",
15+
"type": "image/png",
16+
"purpose": "any"
17+
},
18+
{
19+
"src": "icons/icon-512.png",
20+
"sizes": "512x512",
21+
"type": "image/png",
22+
"purpose": "any"
23+
},
24+
{
25+
"src": "icons/icon-512.png",
26+
"sizes": "512x512",
27+
"type": "image/png",
28+
"purpose": "maskable"
29+
}
30+
]
31+
}

app/manifest-zh-CN.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "ASS 子集化工具",
3+
"short_name": "ASS子集化",
4+
"description": "基于浏览器端实现的 ASS/SSA 字幕优化工具,支持绘图指令子集化与字体子集嵌入,纯前端本地处理。",
5+
"start_url": "/ass-subset/",
6+
"scope": "/ass-subset/",
7+
"display": "standalone",
8+
"background_color": "#f6f5f2",
9+
"theme_color": "#c0392b",
10+
"lang": "zh-CN",
11+
"icons": [
12+
{
13+
"src": "icons/icon-192.png",
14+
"sizes": "192x192",
15+
"type": "image/png",
16+
"purpose": "any"
17+
},
18+
{
19+
"src": "icons/icon-512.png",
20+
"sizes": "512x512",
21+
"type": "image/png",
22+
"purpose": "any"
23+
},
24+
{
25+
"src": "icons/icon-512.png",
26+
"sizes": "512x512",
27+
"type": "image/png",
28+
"purpose": "maskable"
29+
}
30+
]
31+
}

0 commit comments

Comments
 (0)