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`)
|
||||
# Syntax: `{type}:{pattern}[,{patternN}][;{type}:{pattern}[,{patternN}]]`
|
||||
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,
|
||||
chapter_ranges = 'openings:30abf964,endings:30abf964,ads:c54e4e80',
|
||||
chapter_range_patterns = 'openings:オープニング;endings:エンディング',
|
||||
languages = 'slang,en',
|
||||
}
|
||||
options = table_shallow_copy(defaults)
|
||||
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
|
||||
fgt, bgt = serialize_rgba(options.foreground_text).color, serialize_rgba(options.background_text).color
|
||||
|
||||
--[[ INTERNATIONALIZATION ]]
|
||||
t = require('uosc_shared/lib/intl')
|
||||
|
||||
--[[ CONFIG ]]
|
||||
|
||||
function create_default_menu()
|
||||
return {
|
||||
{title = 'Subtitles', value = 'script-binding uosc/subtitles'},
|
||||
{title = 'Audio tracks', value = 'script-binding uosc/audio'},
|
||||
{title = 'Stream quality', value = 'script-binding uosc/stream-quality'},
|
||||
{title = 'Playlist', value = 'script-binding uosc/items'},
|
||||
{title = 'Chapters', value = 'script-binding uosc/chapters'},
|
||||
{title = 'Navigation', items = {
|
||||
{title = 'Next', hint = 'playlist or file', value = 'script-binding uosc/next'},
|
||||
{title = 'Prev', hint = 'playlist or file', value = 'script-binding uosc/prev'},
|
||||
{title = 'Delete file & Next', value = 'script-binding uosc/delete-file-next'},
|
||||
{title = 'Delete file & Prev', value = 'script-binding uosc/delete-file-prev'},
|
||||
{title = 'Delete file & Quit', value = 'script-binding uosc/delete-file-quit'},
|
||||
{title = 'Open file', value = 'script-binding uosc/open-file'},
|
||||
{title = t('Subtitles'), value = 'script-binding uosc/subtitles'},
|
||||
{title = t('Audio tracks'), value = 'script-binding uosc/audio'},
|
||||
{title = t('Stream quality'), value = 'script-binding uosc/stream-quality'},
|
||||
{title = t('Playlist'), value = 'script-binding uosc/items'},
|
||||
{title = t('Chapters'), value = 'script-binding uosc/chapters'},
|
||||
{title = t('Navigation'), items = {
|
||||
{title = t('Next'), hint = t('playlist or file'), value = 'script-binding uosc/next'},
|
||||
{title = t('Prev'), hint = t('playlist or file'), value = 'script-binding uosc/prev'},
|
||||
{title = t('Delete file & Next'), value = 'script-binding uosc/delete-file-next'},
|
||||
{title = t('Delete file & Prev'), value = 'script-binding uosc/delete-file-prev'},
|
||||
{title = t('Delete file & Quit'), value = 'script-binding uosc/delete-file-quit'},
|
||||
{title = t('Open file'), value = 'script-binding uosc/open-file'},
|
||||
},},
|
||||
{title = 'Utils', items = {
|
||||
{title = 'Aspect ratio', items = {
|
||||
{title = 'Default', value = 'set video-aspect-override "-1"'},
|
||||
{title = t('Utils'), items = {
|
||||
{title = t('Aspect ratio'), items = {
|
||||
{title = t('Default'), value = 'set video-aspect-override "-1"'},
|
||||
{title = '16:9', value = 'set video-aspect-override "16:9"'},
|
||||
{title = '4:3', value = 'set video-aspect-override "4:3"'},
|
||||
{title = '2.35:1', value = 'set video-aspect-override "2.35:1"'},
|
||||
},},
|
||||
{title = 'Audio devices', value = 'script-binding uosc/audio-device'},
|
||||
{title = 'Editions', value = 'script-binding uosc/editions'},
|
||||
{title = 'Screenshot', value = 'async screenshot'},
|
||||
{title = 'Show in directory', value = 'script-binding uosc/show-in-directory'},
|
||||
{title = 'Open config folder', value = 'script-binding uosc/open-config-directory'},
|
||||
{title = t('Audio devices'), value = 'script-binding uosc/audio-device'},
|
||||
{title = t('Editions'), value = 'script-binding uosc/editions'},
|
||||
{title = t('Screenshot'), value = 'async screenshot'},
|
||||
{title = t('Show in directory'), value = 'script-binding uosc/show-in-directory'},
|
||||
{title = t('Open config folder'), value = 'script-binding uosc/open-config-directory'},
|
||||
},},
|
||||
{title = 'Quit', value = 'quit'},
|
||||
{title = t('Quit'), value = 'quit'},
|
||||
}
|
||||
end
|
||||
|
||||
@@ -222,6 +226,7 @@ config = {
|
||||
local title_parts = split(title or '', ' *> *')
|
||||
|
||||
for index, title_part in ipairs(#title_parts > 0 and title_parts or {''}) do
|
||||
title_part = t(title_part)
|
||||
if index < #title_parts then
|
||||
submenu_id = submenu_id .. title_part
|
||||
|
||||
@@ -987,7 +992,7 @@ bind_command('editions', create_self_updating_menu_opener({
|
||||
local items = {}
|
||||
for _, edition in ipairs(editions or {}) do
|
||||
items[#items + 1] = {
|
||||
title = edition.title or 'Edition',
|
||||
title = edition.title or t('Edition'),
|
||||
hint = tostring(edition.id + 1),
|
||||
value = edition.id,
|
||||
active = edition.id == current_id,
|
||||
|
@@ -65,7 +65,7 @@ function Controls:init()
|
||||
for i, item in ipairs(items) do
|
||||
local config = shorthands[item.config] and shorthands[item.config] or item.config
|
||||
local config_tooltip = split(config, ' *%? *')
|
||||
local tooltip = config_tooltip[2]
|
||||
local tooltip = t(config_tooltip[2])
|
||||
config = shorthands[config_tooltip[1]]
|
||||
and split(shorthands[config_tooltip[1]], ' *%? *')[1] or config_tooltip[1]
|
||||
local config_badge = split(config, ' *# *')
|
||||
|
@@ -799,7 +799,7 @@ function Menu:render()
|
||||
if draw_title then
|
||||
local title_ay = ay - self.item_height
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
@@ -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
|
||||
-- open an issue.
|
||||
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
|
||||
end
|
||||
|
||||
@@ -108,12 +108,12 @@ function create_select_tracklist_type_menu_opener(menu_title, track_type, track_
|
||||
h(track.codec)
|
||||
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.forced then h('forced') end
|
||||
if track.default then h('default') end
|
||||
if track.external then h('external') end
|
||||
if track.forced then h(t('forced')) end
|
||||
if track.default then h(t('default')) end
|
||||
if track.external then h(t('external')) end
|
||||
|
||||
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, ', '),
|
||||
value = track.id,
|
||||
active = track.selected,
|
||||
@@ -181,10 +181,10 @@ function open_file_navigation_menu(directory_path, handle_select, opts)
|
||||
|
||||
if is_root 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
|
||||
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
|
||||
|
||||
local back_path = items[#items] and items[#items].value
|
||||
@@ -276,7 +276,7 @@ function open_drives_menu(handle_select, opts)
|
||||
if drive then
|
||||
local drive_path = normalize_path(drive)
|
||||
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
|
||||
end
|
||||
@@ -286,7 +286,7 @@ function open_drives_menu(handle_select, opts)
|
||||
end
|
||||
|
||||
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
|
||||
)
|
||||
end
|
||||
|
Reference in New Issue
Block a user