Added project

This commit is contained in:
Marc Gilleron 2018-11-13 21:37:26 +00:00
commit d41fb3e786
16 changed files with 1337 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.import/

View File

@ -0,0 +1,8 @@
[plugin]
name="Translation Editor"
description="Integrated translations editor"
author="Marc Gilleron"
version="0.1"
script="tools/plugin.gd"

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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], "\""))

View File

@ -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()

View File

@ -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"]

View 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

View 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"]

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

29
icon.png.import Normal file
View 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
View 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"