feat: internationalization (#518)
Adds `languages` option to specify localization language priority. Built in languages can be found in `scripts/uosc_shared/intl`.
This commit is contained in:

committed by
GitHub

parent
f274101fbd
commit
3c70ffd927
@@ -219,3 +219,9 @@ chapter_ranges=openings:30abf964,endings:30abf964,ads:c54e4e80
|
|||||||
# Add alternative lua patterns to identify beginnings of simple chapter ranges (except for `ads`)
|
# Add alternative lua patterns to identify beginnings of simple chapter ranges (except for `ads`)
|
||||||
# Syntax: `{type}:{pattern}[,{patternN}][;{type}:{pattern}[,{patternN}]]`
|
# Syntax: `{type}:{pattern}[,{patternN}][;{type}:{pattern}[,{patternN}]]`
|
||||||
chapter_range_patterns=openings:オープニング;endings:エンディング
|
chapter_range_patterns=openings:オープニング;endings:エンディング
|
||||||
|
|
||||||
|
# Localization language priority from highest to lowest.
|
||||||
|
# Built in languages can be found in `uosc_shared/intl`.
|
||||||
|
# `slang` is a keyword to inherit values from `--slang` mpv config.
|
||||||
|
# Supports paths to custom json files: `languages=~~/custom.json,slang,en`
|
||||||
|
languages=slang,en
|
||||||
|
@@ -109,6 +109,7 @@ defaults = {
|
|||||||
adjust_osd_margins = true,
|
adjust_osd_margins = true,
|
||||||
chapter_ranges = 'openings:30abf964,endings:30abf964,ads:c54e4e80',
|
chapter_ranges = 'openings:30abf964,endings:30abf964,ads:c54e4e80',
|
||||||
chapter_range_patterns = 'openings:オープニング;endings:エンディング',
|
chapter_range_patterns = 'openings:オープニング;endings:エンディング',
|
||||||
|
languages = 'slang,en',
|
||||||
}
|
}
|
||||||
options = table_shallow_copy(defaults)
|
options = table_shallow_copy(defaults)
|
||||||
opt.read_options(options, 'uosc')
|
opt.read_options(options, 'uosc')
|
||||||
@@ -131,37 +132,40 @@ if options.autoload then mp.commandv('set', 'keep-open-pause', 'no') end
|
|||||||
fg, bg = serialize_rgba(options.foreground).color, serialize_rgba(options.background).color
|
fg, bg = serialize_rgba(options.foreground).color, serialize_rgba(options.background).color
|
||||||
fgt, bgt = serialize_rgba(options.foreground_text).color, serialize_rgba(options.background_text).color
|
fgt, bgt = serialize_rgba(options.foreground_text).color, serialize_rgba(options.background_text).color
|
||||||
|
|
||||||
|
--[[ INTERNATIONALIZATION ]]
|
||||||
|
t = require('uosc_shared/lib/intl')
|
||||||
|
|
||||||
--[[ CONFIG ]]
|
--[[ CONFIG ]]
|
||||||
|
|
||||||
function create_default_menu()
|
function create_default_menu()
|
||||||
return {
|
return {
|
||||||
{title = 'Subtitles', value = 'script-binding uosc/subtitles'},
|
{title = t('Subtitles'), value = 'script-binding uosc/subtitles'},
|
||||||
{title = 'Audio tracks', value = 'script-binding uosc/audio'},
|
{title = t('Audio tracks'), value = 'script-binding uosc/audio'},
|
||||||
{title = 'Stream quality', value = 'script-binding uosc/stream-quality'},
|
{title = t('Stream quality'), value = 'script-binding uosc/stream-quality'},
|
||||||
{title = 'Playlist', value = 'script-binding uosc/items'},
|
{title = t('Playlist'), value = 'script-binding uosc/items'},
|
||||||
{title = 'Chapters', value = 'script-binding uosc/chapters'},
|
{title = t('Chapters'), value = 'script-binding uosc/chapters'},
|
||||||
{title = 'Navigation', items = {
|
{title = t('Navigation'), items = {
|
||||||
{title = 'Next', hint = 'playlist or file', value = 'script-binding uosc/next'},
|
{title = t('Next'), hint = t('playlist or file'), value = 'script-binding uosc/next'},
|
||||||
{title = 'Prev', hint = 'playlist or file', value = 'script-binding uosc/prev'},
|
{title = t('Prev'), hint = t('playlist or file'), value = 'script-binding uosc/prev'},
|
||||||
{title = 'Delete file & Next', value = 'script-binding uosc/delete-file-next'},
|
{title = t('Delete file & Next'), value = 'script-binding uosc/delete-file-next'},
|
||||||
{title = 'Delete file & Prev', value = 'script-binding uosc/delete-file-prev'},
|
{title = t('Delete file & Prev'), value = 'script-binding uosc/delete-file-prev'},
|
||||||
{title = 'Delete file & Quit', value = 'script-binding uosc/delete-file-quit'},
|
{title = t('Delete file & Quit'), value = 'script-binding uosc/delete-file-quit'},
|
||||||
{title = 'Open file', value = 'script-binding uosc/open-file'},
|
{title = t('Open file'), value = 'script-binding uosc/open-file'},
|
||||||
},},
|
},},
|
||||||
{title = 'Utils', items = {
|
{title = t('Utils'), items = {
|
||||||
{title = 'Aspect ratio', items = {
|
{title = t('Aspect ratio'), items = {
|
||||||
{title = 'Default', value = 'set video-aspect-override "-1"'},
|
{title = t('Default'), value = 'set video-aspect-override "-1"'},
|
||||||
{title = '16:9', value = 'set video-aspect-override "16:9"'},
|
{title = '16:9', value = 'set video-aspect-override "16:9"'},
|
||||||
{title = '4:3', value = 'set video-aspect-override "4:3"'},
|
{title = '4:3', value = 'set video-aspect-override "4:3"'},
|
||||||
{title = '2.35:1', value = 'set video-aspect-override "2.35:1"'},
|
{title = '2.35:1', value = 'set video-aspect-override "2.35:1"'},
|
||||||
},},
|
},},
|
||||||
{title = 'Audio devices', value = 'script-binding uosc/audio-device'},
|
{title = t('Audio devices'), value = 'script-binding uosc/audio-device'},
|
||||||
{title = 'Editions', value = 'script-binding uosc/editions'},
|
{title = t('Editions'), value = 'script-binding uosc/editions'},
|
||||||
{title = 'Screenshot', value = 'async screenshot'},
|
{title = t('Screenshot'), value = 'async screenshot'},
|
||||||
{title = 'Show in directory', value = 'script-binding uosc/show-in-directory'},
|
{title = t('Show in directory'), value = 'script-binding uosc/show-in-directory'},
|
||||||
{title = 'Open config folder', value = 'script-binding uosc/open-config-directory'},
|
{title = t('Open config folder'), value = 'script-binding uosc/open-config-directory'},
|
||||||
},},
|
},},
|
||||||
{title = 'Quit', value = 'quit'},
|
{title = t('Quit'), value = 'quit'},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -222,6 +226,7 @@ config = {
|
|||||||
local title_parts = split(title or '', ' *> *')
|
local title_parts = split(title or '', ' *> *')
|
||||||
|
|
||||||
for index, title_part in ipairs(#title_parts > 0 and title_parts or {''}) do
|
for index, title_part in ipairs(#title_parts > 0 and title_parts or {''}) do
|
||||||
|
title_part = t(title_part)
|
||||||
if index < #title_parts then
|
if index < #title_parts then
|
||||||
submenu_id = submenu_id .. title_part
|
submenu_id = submenu_id .. title_part
|
||||||
|
|
||||||
@@ -987,7 +992,7 @@ bind_command('editions', create_self_updating_menu_opener({
|
|||||||
local items = {}
|
local items = {}
|
||||||
for _, edition in ipairs(editions or {}) do
|
for _, edition in ipairs(editions or {}) do
|
||||||
items[#items + 1] = {
|
items[#items + 1] = {
|
||||||
title = edition.title or 'Edition',
|
title = edition.title or t('Edition'),
|
||||||
hint = tostring(edition.id + 1),
|
hint = tostring(edition.id + 1),
|
||||||
value = edition.id,
|
value = edition.id,
|
||||||
active = edition.id == current_id,
|
active = edition.id == current_id,
|
||||||
|
@@ -65,7 +65,7 @@ function Controls:init()
|
|||||||
for i, item in ipairs(items) do
|
for i, item in ipairs(items) do
|
||||||
local config = shorthands[item.config] and shorthands[item.config] or item.config
|
local config = shorthands[item.config] and shorthands[item.config] or item.config
|
||||||
local config_tooltip = split(config, ' *%? *')
|
local config_tooltip = split(config, ' *%? *')
|
||||||
local tooltip = config_tooltip[2]
|
local tooltip = t(config_tooltip[2])
|
||||||
config = shorthands[config_tooltip[1]]
|
config = shorthands[config_tooltip[1]]
|
||||||
and split(shorthands[config_tooltip[1]], ' *%? *')[1] or config_tooltip[1]
|
and split(shorthands[config_tooltip[1]], ' *%? *')[1] or config_tooltip[1]
|
||||||
local config_badge = split(config, ' *# *')
|
local config_badge = split(config, ' *# *')
|
||||||
|
@@ -799,7 +799,7 @@ function Menu:render()
|
|||||||
if draw_title then
|
if draw_title then
|
||||||
local title_ay = ay - self.item_height
|
local title_ay = ay - self.item_height
|
||||||
local title_height = self.item_height - 3
|
local title_height = self.item_height - 3
|
||||||
menu.ass_safe_title = menu.ass_safe_title or ass_escape(menu.title)
|
menu.ass_safe_title = t(menu.ass_safe_title or ass_escape(menu.title))
|
||||||
|
|
||||||
-- Background
|
-- Background
|
||||||
ass:rect(ax + 2, title_ay, bx - 2, title_ay + title_height, {
|
ass:rect(ax + 2, title_ay, bx - 2, title_ay + title_height, {
|
||||||
|
50
scripts/uosc_shared/intl/zh-hans.json
Normal file
50
scripts/uosc_shared/intl/zh-hans.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"Aspect ratio": "纵横比",
|
||||||
|
"Audio": "音频",
|
||||||
|
"Audio device": "音频设备",
|
||||||
|
"Audio devices": "音频设备",
|
||||||
|
"Audio tracks": "音频轨道",
|
||||||
|
"Chapters": "章节",
|
||||||
|
"Default": "默认",
|
||||||
|
"Delete file & Next": "删除文件并播放下一个",
|
||||||
|
"Delete file & Prev": "删除文件并播放上一个",
|
||||||
|
"Delete file & Quit": "删除文件并退出",
|
||||||
|
"Disabled": "禁用",
|
||||||
|
"Drives": "驱动器",
|
||||||
|
"Edition": "版本",
|
||||||
|
"Editions": "版本",
|
||||||
|
"First": "第一个",
|
||||||
|
"Fullscreen": "全屏",
|
||||||
|
"Last": "最后一个",
|
||||||
|
"Load": "加载",
|
||||||
|
"Load audio": "加载音频",
|
||||||
|
"Load subtitles": "加载字幕",
|
||||||
|
"Load video": "加载视频",
|
||||||
|
"Loop file": "单个循环",
|
||||||
|
"Loop playlist": "列表循环",
|
||||||
|
"Menu": "菜单",
|
||||||
|
"Navigation": "导航",
|
||||||
|
"Next": "下一个",
|
||||||
|
"Open config folder": "打开设置文件夹",
|
||||||
|
"Open file": "打开文件",
|
||||||
|
"Playlist": "播放列表",
|
||||||
|
"Playlist/Files": "播放/文件列表",
|
||||||
|
"Prev": "上一个",
|
||||||
|
"Previous": "上一个",
|
||||||
|
"Quit": "退出",
|
||||||
|
"Screenshot": "截图",
|
||||||
|
"Show in directory": "打开所在文件夹",
|
||||||
|
"Shuffle": "乱序",
|
||||||
|
"Stream quality": "流媒体质量",
|
||||||
|
"Subtitles": "字幕",
|
||||||
|
"Track": "轨道",
|
||||||
|
"Utils": "工具",
|
||||||
|
"Video": "视频",
|
||||||
|
"default": "默认",
|
||||||
|
"drive": "磁盘",
|
||||||
|
"external": "外置",
|
||||||
|
"forced": "强制",
|
||||||
|
"open file": "打开文件",
|
||||||
|
"parent dir": "父文件夹",
|
||||||
|
"playlist or file": "播放列表或文件"
|
||||||
|
}
|
61
scripts/uosc_shared/lib/intl.lua
Normal file
61
scripts/uosc_shared/lib/intl.lua
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
local locale = {}
|
||||||
|
|
||||||
|
-- https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/supported-languages?pivots=store-installer-msix#list-of-supported-languages
|
||||||
|
function get_languages()
|
||||||
|
local languages = {}
|
||||||
|
for _, lang in ipairs(split(options.languages, ',')) do
|
||||||
|
if (lang == 'slang') then
|
||||||
|
local slang = mp.get_property_native('slang')
|
||||||
|
if slang then
|
||||||
|
itable_append(languages, slang)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
itable_append(languages, { lang })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return languages
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param path string
|
||||||
|
function get_locale_from_json(path)
|
||||||
|
local expand_path = mp.command_native({ 'expand-path', path })
|
||||||
|
|
||||||
|
local meta, meta_error = utils.file_info(expand_path)
|
||||||
|
if not meta or not meta.is_file then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local json_file = io.open(expand_path, 'r')
|
||||||
|
if not json_file then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local json = json_file:read('*all')
|
||||||
|
json_file:close()
|
||||||
|
|
||||||
|
return utils.parse_json(json)
|
||||||
|
end
|
||||||
|
|
||||||
|
function make_locale()
|
||||||
|
local translations = {}
|
||||||
|
for _, lang in ipairs(get_languages()) do
|
||||||
|
|
||||||
|
if (lang:match('.json$')) then
|
||||||
|
table_assign(translations, get_locale_from_json(lang))
|
||||||
|
else
|
||||||
|
table_assign(translations, get_locale_from_json('~~/scripts/uosc_shared/intl/' .. lang:lower() .. '.json'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return translations
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param text string
|
||||||
|
function t(text)
|
||||||
|
return locale[text] or text
|
||||||
|
end
|
||||||
|
|
||||||
|
locale = make_locale()
|
||||||
|
|
||||||
|
return t
|
@@ -77,7 +77,7 @@ function create_select_tracklist_type_menu_opener(menu_title, track_type, track_
|
|||||||
|
|
||||||
if load_command then
|
if load_command then
|
||||||
items[#items + 1] = {
|
items[#items + 1] = {
|
||||||
title = 'Load', bold = true, italic = true, hint = 'open file', value = '{load}', separator = true,
|
title = t('Load'), bold = true, italic = true, hint = t('open file'), value = '{load}', separator = true,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ function create_select_tracklist_type_menu_opener(menu_title, track_type, track_
|
|||||||
-- If I'm mistaken and there is an active need for this, feel free to
|
-- If I'm mistaken and there is an active need for this, feel free to
|
||||||
-- open an issue.
|
-- open an issue.
|
||||||
if track_type == 'sub' then
|
if track_type == 'sub' then
|
||||||
disabled_item = {title = 'Disabled', italic = true, muted = true, hint = '—', value = nil, active = true}
|
disabled_item = {title = t('Disabled'), italic = true, muted = true, hint = '—', value = nil, active = true}
|
||||||
items[#items + 1] = disabled_item
|
items[#items + 1] = disabled_item
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -108,12 +108,12 @@ function create_select_tracklist_type_menu_opener(menu_title, track_type, track_
|
|||||||
h(track.codec)
|
h(track.codec)
|
||||||
if track['audio-channels'] then h(track['audio-channels'] .. ' channels') end
|
if track['audio-channels'] then h(track['audio-channels'] .. ' channels') end
|
||||||
if track['demux-samplerate'] then h(string.format('%.3gkHz', track['demux-samplerate'] / 1000)) end
|
if track['demux-samplerate'] then h(string.format('%.3gkHz', track['demux-samplerate'] / 1000)) end
|
||||||
if track.forced then h('forced') end
|
if track.forced then h(t('forced')) end
|
||||||
if track.default then h('default') end
|
if track.default then h(t('default')) end
|
||||||
if track.external then h('external') end
|
if track.external then h(t('external')) end
|
||||||
|
|
||||||
items[#items + 1] = {
|
items[#items + 1] = {
|
||||||
title = (track.title and track.title or 'Track ' .. track.id),
|
title = (track.title and track.title or t('Track') .. ' ' .. track.id),
|
||||||
hint = table.concat(hint_values, ', '),
|
hint = table.concat(hint_values, ', '),
|
||||||
value = track.id,
|
value = track.id,
|
||||||
active = track.selected,
|
active = track.selected,
|
||||||
@@ -181,10 +181,10 @@ function open_file_navigation_menu(directory_path, handle_select, opts)
|
|||||||
|
|
||||||
if is_root then
|
if is_root then
|
||||||
if state.platform == 'windows' then
|
if state.platform == 'windows' then
|
||||||
items[#items + 1] = {title = '..', hint = 'Drives', value = '{drives}', separator = true}
|
items[#items + 1] = {title = '..', hint = t('Drives'), value = '{drives}', separator = true}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
items[#items + 1] = {title = '..', hint = 'parent dir', value = directory.dirname, separator = true}
|
items[#items + 1] = {title = '..', hint = t('parent dir'), value = directory.dirname, separator = true}
|
||||||
end
|
end
|
||||||
|
|
||||||
local back_path = items[#items] and items[#items].value
|
local back_path = items[#items] and items[#items].value
|
||||||
@@ -276,7 +276,7 @@ function open_drives_menu(handle_select, opts)
|
|||||||
if drive then
|
if drive then
|
||||||
local drive_path = normalize_path(drive)
|
local drive_path = normalize_path(drive)
|
||||||
items[#items + 1] = {
|
items[#items + 1] = {
|
||||||
title = drive, hint = 'drive', value = drive_path, active = opts.active_path == drive_path,
|
title = drive, hint = t('drive'), value = drive_path, active = opts.active_path == drive_path,
|
||||||
}
|
}
|
||||||
if opts.selected_path == drive_path then selected_index = #items end
|
if opts.selected_path == drive_path then selected_index = #items end
|
||||||
end
|
end
|
||||||
@@ -286,7 +286,7 @@ function open_drives_menu(handle_select, opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return Menu:open(
|
return Menu:open(
|
||||||
{type = opts.type, title = opts.title or 'Drives', items = items, selected_index = selected_index},
|
{type = opts.type, title = opts.title or t('Drives'), items = items, selected_index = selected_index},
|
||||||
handle_select
|
handle_select
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user