mirror of
https://github.com/Relintai/godot_translation_editor.git
synced 2024-11-20 08:37:18 +01:00
Added project
This commit is contained in:
commit
d41fb3e786
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.import/
|
8
addons/zylann.translation_editor/plugin.cfg
Normal file
8
addons/zylann.translation_editor/plugin.cfg
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="Translation Editor"
|
||||||
|
description="Integrated translations editor"
|
||||||
|
author="Marc Gilleron"
|
||||||
|
version="0.1"
|
||||||
|
script="tools/plugin.gd"
|
||||||
|
|
119
addons/zylann.translation_editor/tools/csv_loader.gd
Normal file
119
addons/zylann.translation_editor/tools/csv_loader.gd
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
tool
|
||||||
|
|
||||||
|
static func load_csv_translation(filepath):
|
||||||
|
var f = File.new()
|
||||||
|
var err = f.open(filepath, File.READ)
|
||||||
|
if err != OK:
|
||||||
|
printerr("Could not open ", filepath, " for read, code ", err)
|
||||||
|
return null
|
||||||
|
|
||||||
|
var first_row = f.get_csv_line()
|
||||||
|
if first_row[0] != "id":
|
||||||
|
printerr("Translation file is missing the `id` column")
|
||||||
|
return null
|
||||||
|
|
||||||
|
var languages = PoolStringArray()
|
||||||
|
for i in range(1, len(first_row)):
|
||||||
|
languages.append(first_row[i])
|
||||||
|
|
||||||
|
var ids = []
|
||||||
|
var rows = []
|
||||||
|
while not f.eof_reached():
|
||||||
|
var row = f.get_csv_line()
|
||||||
|
if len(row) < 1 or row[0].strip_edges() == "":
|
||||||
|
printerr("Found an empty row")
|
||||||
|
continue
|
||||||
|
if len(row) < len(first_row):
|
||||||
|
print("Found row smaller than header, resizing")
|
||||||
|
row.resize(len(first_row))
|
||||||
|
ids.append(row[0])
|
||||||
|
var trans = PoolStringArray()
|
||||||
|
for i in range(1, len(row)):
|
||||||
|
trans.append(row[i])
|
||||||
|
rows.append(trans)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
var translations = {}
|
||||||
|
for i in len(ids):
|
||||||
|
var t = {}
|
||||||
|
for language_index in len(rows[i]):
|
||||||
|
t[languages[language_index]] = rows[i][language_index]
|
||||||
|
translations[ids[i]] = { "translations": t, "comments": "" }
|
||||||
|
|
||||||
|
return translations
|
||||||
|
|
||||||
|
|
||||||
|
class _Sorter:
|
||||||
|
func sort(a, b):
|
||||||
|
return a[0] < b[0]
|
||||||
|
|
||||||
|
|
||||||
|
static func save_csv_translation(filepath, data):
|
||||||
|
var languages = {}
|
||||||
|
for id in data:
|
||||||
|
var s = data[id]
|
||||||
|
for language in s.translations:
|
||||||
|
languages[id] = true
|
||||||
|
|
||||||
|
assert(len(data.languages) > 0)
|
||||||
|
|
||||||
|
languages = languages.keys()
|
||||||
|
languages.sort()
|
||||||
|
|
||||||
|
var first_row = []
|
||||||
|
first_row.resize(len(languages) + 1)
|
||||||
|
for i in len(languages):
|
||||||
|
first_row[i + 1] = languages[i]
|
||||||
|
|
||||||
|
var rows = []
|
||||||
|
rows.resize(len(data))
|
||||||
|
|
||||||
|
var row_index = 0
|
||||||
|
for id in data:
|
||||||
|
var s = data[id]
|
||||||
|
var row = []
|
||||||
|
row.resize(len(languages) + 1)
|
||||||
|
row[0] = id
|
||||||
|
for i in len(languages):
|
||||||
|
var text = ""
|
||||||
|
if s.translations.has(languages[i]):
|
||||||
|
text = s.translations[languages[i]]
|
||||||
|
row[i] = text
|
||||||
|
rows[row_index] = row
|
||||||
|
row_index += 1
|
||||||
|
|
||||||
|
var sorter = _Sorter.new()
|
||||||
|
rows.sort_custom(sorter, "sort")
|
||||||
|
|
||||||
|
var delim = ","
|
||||||
|
|
||||||
|
var f = File.new()
|
||||||
|
var err = f.open(filepath, File.WRITE)
|
||||||
|
if err != OK:
|
||||||
|
printerr("Could not open ", filepath, " for write, code ", err)
|
||||||
|
return false
|
||||||
|
|
||||||
|
for h in first_row:
|
||||||
|
f.store_string(str(",", h))
|
||||||
|
f.store_string("\n")
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
for i in len(row):
|
||||||
|
var text = row[i]
|
||||||
|
if i == 0:
|
||||||
|
f.store_string(text)
|
||||||
|
else:
|
||||||
|
f.store_string(",")
|
||||||
|
# Behavior taken from LibreOffice
|
||||||
|
if text.contains(delim):
|
||||||
|
if text.contains('"'):
|
||||||
|
text = text.replace('"', '""')
|
||||||
|
text = str('"', text, '"')
|
||||||
|
f.store_string(text)
|
||||||
|
f.store_string("\n")
|
||||||
|
|
||||||
|
f.close()
|
||||||
|
print("Saved ", filepath)
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="translate(0 -1036.4)">
|
||||||
|
<path transform="translate(0 1036.4)" d="m3 2c-1.1046 0-2 0.8954-2 2v9c0 1.1046 0.89543 2 2 2h9c1.1046 0 1.8184-0.91043 2-2l1-6c0.003977-0.18354-0.042648-0.3412-0.13477-0.5-0.17849-0.30916-0.50825-0.49972-0.86523-0.5h-8c-0.35698 2.824e-4 -0.68674 0.19084-0.86523 0.5-0.092118 0.1588-0.13874 0.3399-0.13477 0.52344l-1 5.9766c-0.091144 0.54473-0.44772 1-1 1s-1-0.4477-1-1v-9c0-0.5523 0.44772-1 1-1h2c0.55228 0 1 0.4477 1 1a1 1 0 0 0 0.29297 0.70703 1 1 0 0 0 0.70703 0.29297h4 1a1 1 0 0 0 -0.29297 -0.70703 1 1 0 0 0 -0.70703 -0.29297h-4c0-1.1046-0.89543-2-2-2h-2z" fill="#e0e0e0"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 728 B |
@ -0,0 +1,29 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon_load.svg-f539f8f7e34373cfd394e1279319f2af.stex"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/zylann.translation_editor/tools/icons/icon_load.svg"
|
||||||
|
dest_files=[ "res://.import/icon_load.svg-f539f8f7e34373cfd394e1279319f2af.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=false
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="translate(0 -1036.4)">
|
||||||
|
<path transform="translate(0 1036.4)" d="m3 1c-1.1046 0-2 0.89543-2 2v10c0 1.1046 0.89543 2 2 2h10c1.1046 0 2-0.89543 2-2v-7-1-1l-3-3h-1v5 1h-8v-6zm1 0v5h3v-5h-3zm4 8c1.1046 0 2 0.89543 2 2 0 1.1046-0.89543 2-2 2s-2-0.89543-2-2c0-1.1046 0.89543-2 2-2z" fill="#e0e0e0"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 417 B |
@ -0,0 +1,29 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon_save.svg-d0c98adea7edb95cd60b5fa2976f910c.stex"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/zylann.translation_editor/tools/icons/icon_save.svg"
|
||||||
|
dest_files=[ "res://.import/icon_save.svg-d0c98adea7edb95cd60b5fa2976f910c.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=false
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
38
addons/zylann.translation_editor/tools/plugin.gd
Normal file
38
addons/zylann.translation_editor/tools/plugin.gd
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
var TranslationEditor = load("res://addons/zylann.translation_editor/tools/translation_editor.tscn")
|
||||||
|
|
||||||
|
var _main_control = null
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree():
|
||||||
|
print("Translation editor plugin Enter tree")
|
||||||
|
|
||||||
|
var editor_interface = get_editor_interface()
|
||||||
|
var base_control = editor_interface.get_base_control()
|
||||||
|
|
||||||
|
_main_control = TranslationEditor.instance()
|
||||||
|
_main_control.configure_for_godot_integration(base_control)
|
||||||
|
_main_control.hide()
|
||||||
|
editor_interface.get_editor_viewport().add_child(_main_control)
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree():
|
||||||
|
# The main control is not freed when the plugin is disabled
|
||||||
|
_main_control.queue_free()
|
||||||
|
_main_control = null
|
||||||
|
|
||||||
|
|
||||||
|
func has_main_screen():
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func get_plugin_name():
|
||||||
|
return "Localization"
|
||||||
|
|
||||||
|
|
||||||
|
func make_visible(visible):
|
||||||
|
_main_control.visible = visible
|
||||||
|
|
||||||
|
|
145
addons/zylann.translation_editor/tools/po_loader.gd
Normal file
145
addons/zylann.translation_editor/tools/po_loader.gd
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
tool
|
||||||
|
|
||||||
|
static func load_po_translation(folder_path, languages):
|
||||||
|
var all_strings = {}
|
||||||
|
|
||||||
|
for language in languages:
|
||||||
|
var filepath = folder_path.plus_file(str(language, ".po"))
|
||||||
|
|
||||||
|
var f = File.new()
|
||||||
|
var err = f.open(filepath)
|
||||||
|
if err != OK:
|
||||||
|
printerr("Could not open file ", filepath, " for read, error ", err)
|
||||||
|
return null
|
||||||
|
|
||||||
|
var comment = ""
|
||||||
|
var msgid = ""
|
||||||
|
var msgstr = ""
|
||||||
|
var last_is_msgid = false
|
||||||
|
var ids = []
|
||||||
|
var translations = []
|
||||||
|
var comments = []
|
||||||
|
|
||||||
|
while not f.eof_reached():
|
||||||
|
var line = f.get_line()
|
||||||
|
|
||||||
|
if line[0] == "#":
|
||||||
|
comment = str(comment, "\n", line.substr(1, len(line) - 1).strip_edges())
|
||||||
|
continue
|
||||||
|
|
||||||
|
var space_index = line.find(" ")
|
||||||
|
|
||||||
|
if line.begins_with("msgid"):
|
||||||
|
msgid = _parse_msg(line.substr(space_index), len(line) - space_index)
|
||||||
|
last_is_msgid = true
|
||||||
|
|
||||||
|
elif line.begin_with("msgstr"):
|
||||||
|
msgstr = _parse_msg(line.substr(space_index), len(line) - space_index)
|
||||||
|
last_is_msgid = false
|
||||||
|
|
||||||
|
elif line.begin_with('"'):
|
||||||
|
if last_is_msgid:
|
||||||
|
msgid = str(msgid, _parse_msg(line))
|
||||||
|
else:
|
||||||
|
msgstr = str(msgstr, _parse_msg(line))
|
||||||
|
|
||||||
|
elif line == "":
|
||||||
|
var s = null
|
||||||
|
if not all_strings.has(msgid):
|
||||||
|
s = {
|
||||||
|
"translations": {},
|
||||||
|
"comments": ""
|
||||||
|
}
|
||||||
|
all_strings[msgid] = s
|
||||||
|
s.translations[language] = msgstr
|
||||||
|
if s.comments == "":
|
||||||
|
s.comments = comment
|
||||||
|
|
||||||
|
comment = ""
|
||||||
|
msgid = ""
|
||||||
|
msgstr = ""
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Unhandled .po line: ", line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
return all_strings
|
||||||
|
|
||||||
|
|
||||||
|
static func _parse_msg(s):
|
||||||
|
s = s.strip_edges()
|
||||||
|
assert(s[0] == '"')
|
||||||
|
var end = s.rfind('"')
|
||||||
|
var msg = s.substr(1, end - 1)
|
||||||
|
return msg.c_unescape().replace('\\"', '"')
|
||||||
|
|
||||||
|
|
||||||
|
class _Sorter:
|
||||||
|
func sort(a, b):
|
||||||
|
return a[0] < b[0]
|
||||||
|
|
||||||
|
|
||||||
|
static func save_po_translations(folder_path, translations, languages_to_save):
|
||||||
|
var sorter = _Sorter.new()
|
||||||
|
|
||||||
|
for language in languages_to_save:
|
||||||
|
|
||||||
|
var f = File.new()
|
||||||
|
var filepath = folder_path.plus_file(str(language, ".po"))
|
||||||
|
var err = f.open(filepath, File.WRITE)
|
||||||
|
if err != OK:
|
||||||
|
printerr("Could not open file ", filepath, " for write, error ", err)
|
||||||
|
continue
|
||||||
|
|
||||||
|
var items = []
|
||||||
|
|
||||||
|
for id in translations:
|
||||||
|
var s = translations[id]
|
||||||
|
if not s.translations.has(language):
|
||||||
|
continue
|
||||||
|
items.append([id, s.translations[language], s.comments])
|
||||||
|
|
||||||
|
items.sort_custom(sorter, "sort")
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
|
||||||
|
var comment = item[2]
|
||||||
|
if comment != "":
|
||||||
|
var comment_lines = comment.split("\n")
|
||||||
|
for line in comment_lines:
|
||||||
|
f.store_line(str("# ", line))
|
||||||
|
|
||||||
|
_write_msg(f, "msgid", item[0])
|
||||||
|
_write_msg(f, "msgstr", item[1])
|
||||||
|
|
||||||
|
f.store_line("")
|
||||||
|
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
static func _write_msg(f, msgtype, msg):
|
||||||
|
var lines = msg.split("\n")
|
||||||
|
if len(lines) > 1:
|
||||||
|
for i in range(0, len(lines) - 1):
|
||||||
|
lines[i] = str(lines[i], "\n")
|
||||||
|
|
||||||
|
# This is just to avoid too long lines
|
||||||
|
# if len(lines) > 1:
|
||||||
|
# var rlines = []
|
||||||
|
# for i in len(rlines):
|
||||||
|
# var line = rlines[i]
|
||||||
|
# var maxlen = 78
|
||||||
|
# if i == 0:
|
||||||
|
# maxlen -= len(msgtype) + 1
|
||||||
|
# while len(line) > maxlen:
|
||||||
|
# line = line.substr(0, maxlen)
|
||||||
|
# rlines.append(line)
|
||||||
|
# rlines.append(line)
|
||||||
|
# lines = rlines
|
||||||
|
|
||||||
|
for i in len(lines):
|
||||||
|
lines[i] = lines[i].c_escape().replace('"', '\\"')
|
||||||
|
|
||||||
|
f.store_line(str(msgtype, " \"", lines[0], "\""))
|
||||||
|
for i in range(1, len(lines)):
|
||||||
|
f.store_line(str(" \"", lines[i], "\""))
|
@ -0,0 +1,73 @@
|
|||||||
|
tool
|
||||||
|
extends WindowDialog
|
||||||
|
|
||||||
|
signal submitted(str_id, prev_str_id)
|
||||||
|
|
||||||
|
onready var _line_edit = get_node("VBoxContainer/LineEdit")
|
||||||
|
onready var _ok_button = get_node("VBoxContainer/Buttons/OkButton")
|
||||||
|
onready var _hint_label = get_node("VBoxContainer/HintLabel")
|
||||||
|
|
||||||
|
var _validator_func = null
|
||||||
|
var _prev_str_id = null
|
||||||
|
|
||||||
|
|
||||||
|
func set_replaced_str_id(str_id):
|
||||||
|
assert(typeof(str_id) == TYPE_STRING or str_id == null)
|
||||||
|
_prev_str_id = str_id
|
||||||
|
if typeof(str_id) == TYPE_STRING:
|
||||||
|
_line_edit.text = str_id
|
||||||
|
|
||||||
|
|
||||||
|
func set_validator(f):
|
||||||
|
_validator_func = f
|
||||||
|
|
||||||
|
|
||||||
|
func _notification(what):
|
||||||
|
if what == NOTIFICATION_VISIBILITY_CHANGED:
|
||||||
|
if visible:
|
||||||
|
if _prev_str_id == null:
|
||||||
|
window_title = "New string ID"
|
||||||
|
else:
|
||||||
|
window_title = str("Replace `", _prev_str_id, "`")
|
||||||
|
_line_edit.grab_focus()
|
||||||
|
_validate()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_LineEdit_text_changed(new_text):
|
||||||
|
_validate()
|
||||||
|
|
||||||
|
|
||||||
|
func _validate():
|
||||||
|
var new_text = _line_edit.text.strip_edges()
|
||||||
|
var valid = not new_text.empty()
|
||||||
|
var hint_message = ""
|
||||||
|
|
||||||
|
if _validator_func != null:
|
||||||
|
var res = _validator_func.call_func(new_text)
|
||||||
|
assert(typeof(res) == TYPE_BOOL or typeof(res) == TYPE_STRING)
|
||||||
|
if typeof(res) != TYPE_BOOL or res == false:
|
||||||
|
hint_message = res
|
||||||
|
valid = false
|
||||||
|
|
||||||
|
_ok_button.disabled = not valid
|
||||||
|
_hint_label.text = hint_message
|
||||||
|
# Note: hiding the label would shift up other controls in the container
|
||||||
|
|
||||||
|
|
||||||
|
func _on_LineEdit_text_entered(new_text):
|
||||||
|
submit()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_OkButton_pressed():
|
||||||
|
submit()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_CancelButton_pressed():
|
||||||
|
hide()
|
||||||
|
|
||||||
|
|
||||||
|
func submit():
|
||||||
|
var s = _line_edit.text.strip_edges()
|
||||||
|
emit_signal("submitted", s, _prev_str_id)
|
||||||
|
hide()
|
||||||
|
|
@ -0,0 +1,185 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/zylann.translation_editor/tools/string_edition_dialog.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="StringEditionDialog" type="WindowDialog"]
|
||||||
|
|
||||||
|
visible = false
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 118.0
|
||||||
|
margin_top = 154.0
|
||||||
|
margin_right = 446.0
|
||||||
|
margin_bottom = 259.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
popup_exclusive = false
|
||||||
|
window_title = "New string"
|
||||||
|
resizable = false
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="." index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_left = 8.0
|
||||||
|
margin_top = 8.0
|
||||||
|
margin_right = -8.0
|
||||||
|
margin_bottom = -32.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
_sections_unfolded = [ "Margin" ]
|
||||||
|
|
||||||
|
[node name="HintLabel" type="Label" parent="VBoxContainer" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 312.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 2
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 4
|
||||||
|
text = "Already existing"
|
||||||
|
percent_visible = 1.0
|
||||||
|
lines_skipped = 0
|
||||||
|
max_lines_visible = -1
|
||||||
|
|
||||||
|
[node name="LineEdit" type="LineEdit" parent="VBoxContainer" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 312.0
|
||||||
|
margin_bottom = 42.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 1
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
focus_mode = 2
|
||||||
|
context_menu_enabled = true
|
||||||
|
placeholder_alpha = 0.6
|
||||||
|
caret_blink = false
|
||||||
|
caret_blink_speed = 0.65
|
||||||
|
caret_position = 0
|
||||||
|
|
||||||
|
[node name="Spacer" type="Control" parent="VBoxContainer" index="2"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 46.0
|
||||||
|
margin_right = 312.0
|
||||||
|
margin_bottom = 54.0
|
||||||
|
rect_min_size = Vector2( 0, 8 )
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
_sections_unfolded = [ "Rect" ]
|
||||||
|
|
||||||
|
[node name="Buttons" type="HBoxContainer" parent="VBoxContainer" index="3"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 58.0
|
||||||
|
margin_right = 312.0
|
||||||
|
margin_bottom = 78.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
custom_constants/separation = 16
|
||||||
|
alignment = 1
|
||||||
|
_sections_unfolded = [ "custom_constants" ]
|
||||||
|
|
||||||
|
[node name="OkButton" type="Button" parent="VBoxContainer/Buttons" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 48.0
|
||||||
|
margin_right = 148.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_min_size = Vector2( 100, 0 )
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
toggle_mode = false
|
||||||
|
enabled_focus_mode = 2
|
||||||
|
shortcut = null
|
||||||
|
group = null
|
||||||
|
text = "OK"
|
||||||
|
flat = false
|
||||||
|
align = 1
|
||||||
|
_sections_unfolded = [ "Rect" ]
|
||||||
|
|
||||||
|
[node name="CancelButton" type="Button" parent="VBoxContainer/Buttons" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 164.0
|
||||||
|
margin_right = 264.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_min_size = Vector2( 100, 0 )
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
toggle_mode = false
|
||||||
|
enabled_focus_mode = 2
|
||||||
|
shortcut = null
|
||||||
|
group = null
|
||||||
|
text = "Cancel"
|
||||||
|
flat = false
|
||||||
|
align = 1
|
||||||
|
_sections_unfolded = [ "Rect" ]
|
||||||
|
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/LineEdit" to="." method="_on_LineEdit_text_changed"]
|
||||||
|
|
||||||
|
[connection signal="text_entered" from="VBoxContainer/LineEdit" to="." method="_on_LineEdit_text_entered"]
|
||||||
|
|
||||||
|
[connection signal="pressed" from="VBoxContainer/Buttons/OkButton" to="." method="_on_OkButton_pressed"]
|
||||||
|
|
||||||
|
[connection signal="pressed" from="VBoxContainer/Buttons/CancelButton" to="." method="_on_CancelButton_pressed"]
|
||||||
|
|
||||||
|
|
213
addons/zylann.translation_editor/tools/translation_editor.gd
Normal file
213
addons/zylann.translation_editor/tools/translation_editor.gd
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
tool
|
||||||
|
extends Panel
|
||||||
|
|
||||||
|
const CsvLoader = preload("csv_loader.gd")
|
||||||
|
const PoLoader = preload("po_loader.gd")
|
||||||
|
const StringEditionDialog = preload("string_edition_dialog.tscn")
|
||||||
|
|
||||||
|
const MENU_FILE_OPEN = 0
|
||||||
|
const MENU_FILE_SAVE = 1
|
||||||
|
const MENU_FILE_SAVE_AS = 2
|
||||||
|
|
||||||
|
onready var _file_menu = get_node("VBoxContainer/MenuBar/FileMenu")
|
||||||
|
onready var _edit_menu = get_node("VBoxContainer/MenuBar/EditMenu")
|
||||||
|
onready var _string_list = get_node("VBoxContainer/Main/LeftPane/StringList")
|
||||||
|
onready var _translation_tab_container = \
|
||||||
|
get_node("VBoxContainer/Main/RightPane/VSplitContainer/TranslationTabContainer")
|
||||||
|
onready var _notes_edit = get_node("VBoxContainer/Main/RightPane/VSplitContainer/VBoxContainer/NotesEdit")
|
||||||
|
|
||||||
|
var _string_edit_dialog = null
|
||||||
|
var _open_dialog = null
|
||||||
|
var _save_dialog = null
|
||||||
|
|
||||||
|
# This is set when integrated as a Godot plugin
|
||||||
|
var _base_control = null
|
||||||
|
|
||||||
|
var _data = null
|
||||||
|
# TODO Make this a config of some sort
|
||||||
|
var _languages = ["en", "fr"]
|
||||||
|
var _current_file = null
|
||||||
|
|
||||||
|
var _translation_edits = {}
|
||||||
|
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# I don't want any of this to run in the edited scene (because `tool`)...
|
||||||
|
if Engine.editor_hint and get_parent() is Viewport:
|
||||||
|
return
|
||||||
|
|
||||||
|
_file_menu.get_popup().add_item("Open...", MENU_FILE_OPEN)
|
||||||
|
_file_menu.get_popup().add_item("Save", MENU_FILE_SAVE)
|
||||||
|
_file_menu.get_popup().add_item("Save as...", MENU_FILE_SAVE_AS)
|
||||||
|
_file_menu.get_popup().connect("id_pressed", self, "_on_FileMenu_id_pressed")
|
||||||
|
|
||||||
|
_edit_menu.get_popup().connect("id_pressed", self, "_on_EditMenu_id_pressed")
|
||||||
|
|
||||||
|
var dialogs_parent = self
|
||||||
|
if _base_control != null:
|
||||||
|
dialogs_parent = _base_control
|
||||||
|
self_modulate = Color(0,0,0,0)
|
||||||
|
|
||||||
|
_open_dialog = FileDialog.new()
|
||||||
|
_open_dialog.window_title = "Open translations"
|
||||||
|
_open_dialog.add_filter("*.csv ; CSV files")
|
||||||
|
_open_dialog.add_filter("*.po ; Gettext files")
|
||||||
|
_open_dialog.mode = FileDialog.MODE_OPEN_FILE
|
||||||
|
_open_dialog.connect("file_selected", self, "_on_OpenDialog_file_selected")
|
||||||
|
dialogs_parent.add_child(_open_dialog)
|
||||||
|
|
||||||
|
_save_dialog = FileDialog.new()
|
||||||
|
_save_dialog.window_title = "Save translations"
|
||||||
|
_save_dialog.add_filter("*.csv ; CSV files")
|
||||||
|
_save_dialog.add_filter("*.po ; Gettext files")
|
||||||
|
_save_dialog.mode = FileDialog.MODE_SAVE_FILE
|
||||||
|
_save_dialog.connect("file_selected", self, "_on_SaveDialog_file_selected")
|
||||||
|
dialogs_parent.add_child(_save_dialog)
|
||||||
|
|
||||||
|
_string_edit_dialog = StringEditionDialog.instance()
|
||||||
|
_string_edit_dialog.set_validator(funcref(self, "_validate_new_string_id"))
|
||||||
|
dialogs_parent.add_child(_string_edit_dialog)
|
||||||
|
|
||||||
|
|
||||||
|
func configure_for_godot_integration(base_control):
|
||||||
|
# You have to call this before adding to the tree
|
||||||
|
assert(not is_inside_tree())
|
||||||
|
_base_control = base_control
|
||||||
|
|
||||||
|
|
||||||
|
func _on_FileMenu_id_pressed(id):
|
||||||
|
match id:
|
||||||
|
MENU_FILE_OPEN:
|
||||||
|
_open_dialog.popup_centered_ratio()
|
||||||
|
MENU_FILE_SAVE:
|
||||||
|
if _current_file == null:
|
||||||
|
_save_dialog.popup_centered_ratio()
|
||||||
|
else:
|
||||||
|
save_file(_current_file)
|
||||||
|
MENU_FILE_SAVE_AS:
|
||||||
|
_save_dialog.popup_centered_ratio()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_EditMenu_id_pressed(id):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func _on_OpenDialog_file_selected(filepath):
|
||||||
|
load_file(filepath)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_SaveDialog_file_selected(filepath):
|
||||||
|
save_file(filepath)
|
||||||
|
|
||||||
|
|
||||||
|
func load_file(filepath):
|
||||||
|
var ext = filepath.get_extension()
|
||||||
|
if ext == "po":
|
||||||
|
_data = PoLoader.load_po_translation(filepath)
|
||||||
|
elif ext == "csv":
|
||||||
|
_data = CsvLoader.load_csv_translation(filepath)
|
||||||
|
else:
|
||||||
|
printerr("Unknown file format, cannot load ", filepath)
|
||||||
|
return
|
||||||
|
|
||||||
|
_translation_edits.clear()
|
||||||
|
|
||||||
|
for i in _translation_tab_container.get_child_count():
|
||||||
|
var child = _translation_tab_container.get_child(i)
|
||||||
|
if child is TextEdit:
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
for language in _languages:
|
||||||
|
var edit = TextEdit.new()
|
||||||
|
var tab_index = _translation_tab_container.get_tab_count()
|
||||||
|
_translation_tab_container.add_child(edit)
|
||||||
|
_translation_tab_container.set_tab_title(tab_index, language)
|
||||||
|
_translation_edits[language] = edit
|
||||||
|
|
||||||
|
refresh_list()
|
||||||
|
_current_file = filepath
|
||||||
|
|
||||||
|
|
||||||
|
func save_file(filepath):
|
||||||
|
var ext = filepath.get_extension()
|
||||||
|
if ext == "po":
|
||||||
|
PoLoader.save_po_translations(filepath.get_base_dir(), _data, _languages)
|
||||||
|
elif ext == "csv":
|
||||||
|
CsvLoader.save_csv_translation(_data)
|
||||||
|
else:
|
||||||
|
printerr("Unknown file format, cannot save ", filepath)
|
||||||
|
|
||||||
|
|
||||||
|
func refresh_list():
|
||||||
|
_string_list.clear()
|
||||||
|
var ordered_ids = _data.keys()
|
||||||
|
ordered_ids.sort()
|
||||||
|
for id in ordered_ids:
|
||||||
|
#var i = _string_list.get_item_count()
|
||||||
|
_string_list.add_item(id)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_StringList_item_selected(index):
|
||||||
|
var str_id = _string_list.get_item_text(index)
|
||||||
|
var s = _data[str_id]
|
||||||
|
for language in _languages:
|
||||||
|
var e = _translation_edits[language]
|
||||||
|
if s.translations.has(language):
|
||||||
|
e.text = s.translations[language]
|
||||||
|
else:
|
||||||
|
e.text = ""
|
||||||
|
_notes_edit.text = s.comments
|
||||||
|
|
||||||
|
|
||||||
|
func _on_AddButton_pressed():
|
||||||
|
_string_edit_dialog.set_replaced_str_id(null)
|
||||||
|
_string_edit_dialog.popup_centered()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_RemoveButton_pressed():
|
||||||
|
# TODO Remove string with confirmation
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func _on_RenameButton_pressed():
|
||||||
|
var selected_items = _string_list.get_selected_items()
|
||||||
|
if len(selected_items) == 0:
|
||||||
|
return
|
||||||
|
var str_id = _string_list.get_item_text(selected_items[0])
|
||||||
|
_string_edit_dialog.set_replaced_str_id(str_id)
|
||||||
|
_string_edit_dialog.popup_centered()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_StringEditionDialog_submitted(str_id, prev_str_id):
|
||||||
|
if prev_str_id == null:
|
||||||
|
add_new_string(str_id)
|
||||||
|
else:
|
||||||
|
rename_string(prev_str_id, str_id)
|
||||||
|
|
||||||
|
|
||||||
|
func _validate_new_string_id(str_id):
|
||||||
|
if _data.has(str_id):
|
||||||
|
return "Already existing"
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func add_new_string(strid):
|
||||||
|
assert(not _data.has(strid))
|
||||||
|
var s = {
|
||||||
|
"translations": {},
|
||||||
|
"comments": ""
|
||||||
|
}
|
||||||
|
_data[strid] = s
|
||||||
|
_string_list.add_item(strid)
|
||||||
|
|
||||||
|
|
||||||
|
func rename_string(old_strid, new_strid):
|
||||||
|
assert(_data.has(old_strid))
|
||||||
|
var s = _data[old_strid]
|
||||||
|
_data.erase(old_strid)
|
||||||
|
_data[new_strid] = s
|
||||||
|
for i in _string_list.get_item_count():
|
||||||
|
if _string_list.get_item_text(i) == old_strid:
|
||||||
|
_string_list.set_item_text(i, new_strid)
|
||||||
|
break
|
||||||
|
|
440
addons/zylann.translation_editor/tools/translation_editor.tscn
Normal file
440
addons/zylann.translation_editor/tools/translation_editor.tscn
Normal file
@ -0,0 +1,440 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/zylann.translation_editor/tools/translation_editor.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="TranslationEditor" type="Panel" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 3
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
_sections_unfolded = [ "Margin", "Size Flags" ]
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="." index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_left = 4.0
|
||||||
|
margin_top = 4.0
|
||||||
|
margin_right = -4.0
|
||||||
|
margin_bottom = -4.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
_sections_unfolded = [ "Margin" ]
|
||||||
|
|
||||||
|
[node name="MenuBar" type="HBoxContainer" parent="VBoxContainer" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 792.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
|
||||||
|
[node name="FileMenu" type="MenuButton" parent="VBoxContainer/MenuBar" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 35.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
toggle_mode = false
|
||||||
|
action_mode = 0
|
||||||
|
enabled_focus_mode = 0
|
||||||
|
shortcut = null
|
||||||
|
group = null
|
||||||
|
text = "File"
|
||||||
|
flat = true
|
||||||
|
align = 1
|
||||||
|
items = [ ]
|
||||||
|
|
||||||
|
[node name="EditMenu" type="MenuButton" parent="VBoxContainer/MenuBar" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 39.0
|
||||||
|
margin_right = 75.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
toggle_mode = false
|
||||||
|
action_mode = 0
|
||||||
|
enabled_focus_mode = 0
|
||||||
|
shortcut = null
|
||||||
|
group = null
|
||||||
|
text = "Edit"
|
||||||
|
flat = true
|
||||||
|
align = 1
|
||||||
|
items = [ ]
|
||||||
|
|
||||||
|
[node name="Main" type="HSplitContainer" parent="VBoxContainer" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 24.0
|
||||||
|
margin_right = 792.0
|
||||||
|
margin_bottom = 454.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 3
|
||||||
|
split_offset = 100
|
||||||
|
collapsed = false
|
||||||
|
dragger_visibility = 0
|
||||||
|
_sections_unfolded = [ "Size Flags" ]
|
||||||
|
|
||||||
|
[node name="LeftPane" type="VBoxContainer" parent="VBoxContainer/Main" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 273.0
|
||||||
|
margin_bottom = 430.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
|
||||||
|
[node name="Search" type="LineEdit" parent="VBoxContainer/Main/LeftPane" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 273.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 1
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
focus_mode = 2
|
||||||
|
context_menu_enabled = true
|
||||||
|
placeholder_alpha = 0.6
|
||||||
|
caret_blink = false
|
||||||
|
caret_blink_speed = 0.65
|
||||||
|
caret_position = 0
|
||||||
|
|
||||||
|
[node name="StringList" type="ItemList" parent="VBoxContainer/Main/LeftPane" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 28.0
|
||||||
|
margin_right = 273.0
|
||||||
|
margin_bottom = 406.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = true
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 3
|
||||||
|
items = [ ]
|
||||||
|
select_mode = 0
|
||||||
|
allow_reselect = false
|
||||||
|
icon_mode = 1
|
||||||
|
fixed_icon_size = Vector2( 0, 0 )
|
||||||
|
_sections_unfolded = [ "Size Flags" ]
|
||||||
|
|
||||||
|
[node name="StringListActions" type="HBoxContainer" parent="VBoxContainer/Main/LeftPane" index="2"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 410.0
|
||||||
|
margin_right = 273.0
|
||||||
|
margin_bottom = 430.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
|
||||||
|
[node name="AddButton" type="Button" parent="VBoxContainer/Main/LeftPane/StringListActions" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 37.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
toggle_mode = false
|
||||||
|
enabled_focus_mode = 2
|
||||||
|
shortcut = null
|
||||||
|
group = null
|
||||||
|
text = "Add"
|
||||||
|
flat = false
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="RemoveButton" type="Button" parent="VBoxContainer/Main/LeftPane/StringListActions" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 41.0
|
||||||
|
margin_right = 105.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
toggle_mode = false
|
||||||
|
enabled_focus_mode = 2
|
||||||
|
shortcut = null
|
||||||
|
group = null
|
||||||
|
text = "Remove"
|
||||||
|
flat = false
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="RenameButton" type="Button" parent="VBoxContainer/Main/LeftPane/StringListActions" index="2"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 109.0
|
||||||
|
margin_right = 173.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
toggle_mode = false
|
||||||
|
enabled_focus_mode = 2
|
||||||
|
shortcut = null
|
||||||
|
group = null
|
||||||
|
text = "Rename"
|
||||||
|
flat = false
|
||||||
|
align = 1
|
||||||
|
|
||||||
|
[node name="RightPane" type="VBoxContainer" parent="VBoxContainer/Main" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 285.0
|
||||||
|
margin_right = 792.0
|
||||||
|
margin_bottom = 430.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
|
||||||
|
[node name="VSplitContainer" type="VSplitContainer" parent="VBoxContainer/Main/RightPane" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 507.0
|
||||||
|
margin_bottom = 430.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 3
|
||||||
|
split_offset = 250
|
||||||
|
collapsed = false
|
||||||
|
dragger_visibility = 0
|
||||||
|
_sections_unfolded = [ "Size Flags" ]
|
||||||
|
|
||||||
|
[node name="TranslationTabContainer" type="TabContainer" parent="VBoxContainer/Main/RightPane/VSplitContainer" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 507.0
|
||||||
|
margin_bottom = 286.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
tab_align = 0
|
||||||
|
tabs_visible = true
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/Main/RightPane/VSplitContainer" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 298.0
|
||||||
|
margin_right = 507.0
|
||||||
|
margin_bottom = 430.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/Main/RightPane/VSplitContainer/VBoxContainer" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 507.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 2
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 4
|
||||||
|
text = "Notes"
|
||||||
|
percent_visible = 1.0
|
||||||
|
lines_skipped = 0
|
||||||
|
max_lines_visible = -1
|
||||||
|
|
||||||
|
[node name="NotesEdit" type="TextEdit" parent="VBoxContainer/Main/RightPane/VSplitContainer/VBoxContainer" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 507.0
|
||||||
|
margin_bottom = 132.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 3
|
||||||
|
text = ""
|
||||||
|
readonly = false
|
||||||
|
highlight_current_line = false
|
||||||
|
syntax_highlighting = false
|
||||||
|
show_line_numbers = false
|
||||||
|
highlight_all_occurrences = false
|
||||||
|
override_selected_font_color = false
|
||||||
|
context_menu_enabled = true
|
||||||
|
smooth_scrolling = false
|
||||||
|
v_scroll_speed = 80.0
|
||||||
|
hiding_enabled = 0
|
||||||
|
wrap_lines = false
|
||||||
|
caret_block_mode = false
|
||||||
|
caret_blink = false
|
||||||
|
caret_blink_speed = 0.65
|
||||||
|
caret_moving_by_right_click = true
|
||||||
|
_sections_unfolded = [ "Size Flags" ]
|
||||||
|
|
||||||
|
[node name="StatusBar" type="HBoxContainer" parent="VBoxContainer" index="2"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 458.0
|
||||||
|
margin_right = 792.0
|
||||||
|
margin_bottom = 472.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/StatusBar" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_right = 39.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 2
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 4
|
||||||
|
text = "Status"
|
||||||
|
percent_visible = 1.0
|
||||||
|
lines_skipped = 0
|
||||||
|
max_lines_visible = -1
|
||||||
|
|
||||||
|
[connection signal="item_selected" from="VBoxContainer/Main/LeftPane/StringList" to="." method="_on_StringList_item_selected"]
|
||||||
|
|
||||||
|
[connection signal="pressed" from="VBoxContainer/Main/LeftPane/StringListActions/AddButton" to="." method="_on_AddButton_pressed"]
|
||||||
|
|
||||||
|
[connection signal="pressed" from="VBoxContainer/Main/LeftPane/StringListActions/RemoveButton" to="." method="_on_RemoveButton_pressed"]
|
||||||
|
|
||||||
|
[connection signal="pressed" from="VBoxContainer/Main/LeftPane/StringListActions/RenameButton" to="." method="_on_RenameButton_pressed"]
|
||||||
|
|
||||||
|
|
29
icon.png.import
Normal file
29
icon.png.import
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.png"
|
||||||
|
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
18
project.godot
Normal file
18
project.godot
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=3
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="TranslationEditor"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
environment/default_environment="res://default_env.tres"
|
Loading…
Reference in New Issue
Block a user