fix: convert katakana proper nouns (e.g. ヨルシカ) to romaji in sort tags
When kuromoji marks a katakana token as reading '*' (unknown word — common for band names like ヨルシカ), the code fell back to the surface_form which is still katakana. _hiraToRomaji can't handle katakana so it passed through unchanged, causing sort tags to show ヨルシカ instead of Yorushika. Fix: if the surface_form contains katakana and reading is *, convert it mechanically via _kataToHira + _hiraToRomaji — katakana-to-romaji is always unambiguous and needs no dictionary. Also add a Japanese-char guard in the frontend when applying romaji index values, so stale cache entries can never overwrite correct values with Japanese. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
e6d85e63a8
commit
212491aa89
2 files changed
+16
-6
No files matched your search
@@ -65,12 +65,16 @@ function _hiraToRomaji(str) {
|
|||||||
|
|
||||||
const JP_RE = /[-ヿ㐀-䶿一-鿿-]/;
|
const JP_RE = /[-ヿ㐀-䶿一-鿿-]/;
|
||||||
|
|
||||||
|
const KATA_RE = /[ァ-ヶ]/;
|
||||||
|
|
||||||
function toRomaji(text) {
|
function toRomaji(text) {
|
||||||
if (!text || !_tokenizer || !JP_RE.test(text)) return text || '';
|
if (!text || !_tokenizer || !JP_RE.test(text)) return text || '';
|
||||||
const tokens = _tokenizer.tokenize(text);
|
const tokens = _tokenizer.tokenize(text);
|
||||||
const hira = tokens.map(t => {
|
const hira = tokens.map(t => {
|
||||||
const r = t.reading;
|
const r = t.reading;
|
||||||
return (r && r !== '*') ? _kataToHira(r) : t.surface_form;
|
if (r && r !== '*') return _kataToHira(r);
|
||||||
|
if (KATA_RE.test(t.surface_form)) return _kataToHira(t.surface_form); // katakana proper noun
|
||||||
|
return t.surface_form;
|
||||||
}).join('');
|
}).join('');
|
||||||
return _hiraToRomaji(hira).toLowerCase();
|
return _hiraToRomaji(hira).toLowerCase();
|
||||||
}
|
}
|
||||||
@@ -81,7 +85,10 @@ function romajiForStorage(text) {
|
|||||||
const tokens = _tokenizer.tokenize(text);
|
const tokens = _tokenizer.tokenize(text);
|
||||||
const parts = tokens.map(t => {
|
const parts = tokens.map(t => {
|
||||||
const r = t.reading;
|
const r = t.reading;
|
||||||
if (!r || r === '*') return t.surface_form; // ASCII — keep original
|
if (!r || r === '*') {
|
||||||
|
if (KATA_RE.test(t.surface_form)) return _hiraToRomaji(_kataToHira(t.surface_form)); // katakana proper noun
|
||||||
|
return t.surface_form; // ASCII — keep original
|
||||||
|
}
|
||||||
return _hiraToRomaji(_kataToHira(r)); // Japanese — convert (lowercase)
|
return _hiraToRomaji(_kataToHira(r)); // Japanese — convert (lowercase)
|
||||||
});
|
});
|
||||||
// Add space between adjacent alphabetic segments (word separation for names/titles)
|
// Add space between adjacent alphabetic segments (word separation for names/titles)
|
||||||
|
|||||||
@@ -364,10 +364,13 @@ export function toggleInfoEdit() {
|
|||||||
fetchRomajiIndex().catch(() => null).then(() => {
|
fetchRomajiIndex().catch(() => null).then(() => {
|
||||||
const rm = romajiLookup(_sId);
|
const rm = romajiLookup(_sId);
|
||||||
if (rm) {
|
if (rm) {
|
||||||
document.getElementById('ie-titlesort').value = rm.titleRomaji || '';
|
const _jp = /[ぁ-んァ-ン一-龯]/;
|
||||||
document.getElementById('ie-artistsort').value = rm.artistRomaji || '';
|
if (rm.titleRomaji && !_jp.test(rm.titleRomaji)) document.getElementById('ie-titlesort').value = rm.titleRomaji;
|
||||||
document.getElementById('ie-albumartistsort').value = rm.artistRomaji || '';
|
if (rm.artistRomaji && !_jp.test(rm.artistRomaji)) {
|
||||||
document.getElementById('ie-albumsort').value = rm.albumRomaji || '';
|
document.getElementById('ie-artistsort').value = rm.artistRomaji;
|
||||||
|
document.getElementById('ie-albumartistsort').value = rm.artistRomaji;
|
||||||
|
}
|
||||||
|
if (rm.albumRomaji && !_jp.test(rm.albumRomaji)) document.getElementById('ie-albumsort').value = rm.albumRomaji;
|
||||||
}
|
}
|
||||||
if (!S.cfg.backendUrl || !_sId) return null;
|
if (!S.cfg.backendUrl || !_sId) return null;
|
||||||
const p = new URLSearchParams({ ndUrl: S.cfg.url, user: S.cfg.user, pass: S.cfg.pass, songId: _sId });
|
const p = new URLSearchParams({ ndUrl: S.cfg.url, user: S.cfg.user, pass: S.cfg.pass, songId: _sId });
|
||||||
|
|||||||
Reference in new issue
Block a user