diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/editor_audio_buses.cpp | 4 | ||||
-rw-r--r-- | editor/editor_data.cpp | 4 | ||||
-rw-r--r-- | editor/editor_profiler.cpp | 6 | ||||
-rw-r--r-- | editor/plugins/canvas_item_editor_plugin.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.cpp | 9 | ||||
-rw-r--r-- | editor/plugins/spatial_editor_plugin.cpp | 8 | ||||
-rw-r--r-- | editor/plugins/spatial_editor_plugin.h | 3 | ||||
-rw-r--r-- | editor/plugins/tile_map_editor_plugin.cpp | 92 | ||||
-rw-r--r-- | editor/plugins/tile_map_editor_plugin.h | 2 | ||||
-rw-r--r-- | editor/plugins/tile_set_editor_plugin.cpp | 56 | ||||
-rw-r--r-- | editor/property_editor.cpp | 2 | ||||
-rw-r--r-- | editor/script_editor_debugger.cpp | 2 | ||||
-rw-r--r-- | editor/settings_config_dialog.cpp | 6 | ||||
-rw-r--r-- | editor/translations/README.md | 7 |
14 files changed, 105 insertions, 98 deletions
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index de64c11308..6e507fac9b 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -251,7 +251,7 @@ void EditorAudioBus::_volume_db_changed(float p_db) { updating_bus = true; UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action("Change Audio Bus Volume", UndoRedo::MERGE_ENDS); + ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS); ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index())); ur->add_do_method(buses, "_update_bus", get_index()); @@ -812,7 +812,7 @@ void EditorAudioBuses::_update_buses() { EditorAudioBuses *EditorAudioBuses::register_editor() { EditorAudioBuses *audio_buses = memnew(EditorAudioBuses); - EditorNode::get_singleton()->add_bottom_panel_item("Audio", audio_buses); + EditorNode::get_singleton()->add_bottom_panel_item(TTR("Audio"), audio_buses); return audio_buses; } diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 443004f820..49d55e6305 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -690,9 +690,9 @@ Ref<Script> EditorData::get_scene_root_script(int p_idx) const { String EditorData::get_scene_title(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String()); if (!edited_scene[p_idx].root) - return "[empty]"; + return TTR("[empty]"); if (edited_scene[p_idx].root->get_filename() == "") - return "[unsaved]"; + return TTR("[unsaved]"); bool show_ext = EDITOR_DEF("interface/scene_tabs/show_extension", false); String name = edited_scene[p_idx].root->get_filename().get_file(); if (!show_ext) { diff --git a/editor/editor_profiler.cpp b/editor/editor_profiler.cpp index 5d81fc6ea4..71c26244ee 100644 --- a/editor/editor_profiler.cpp +++ b/editor/editor_profiler.cpp @@ -670,13 +670,13 @@ EditorProfiler::EditorProfiler() { variables->set_hide_root(true); variables->set_columns(3); variables->set_column_titles_visible(true); - variables->set_column_title(0, "Name"); + variables->set_column_title(0, TTR("Name")); variables->set_column_expand(0, true); variables->set_column_min_width(0, 60); - variables->set_column_title(1, "Time"); + variables->set_column_title(1, TTR("Time")); variables->set_column_expand(1, false); variables->set_column_min_width(1, 60 * EDSCALE); - variables->set_column_title(2, "Calls"); + variables->set_column_title(2, TTR("Calls")); variables->set_column_expand(2, false); variables->set_column_min_width(2, 60 * EDSCALE); variables->connect("item_edited", this, "_item_edited"); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index d18e97fe83..184ac5d798 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4314,7 +4314,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { show_grid = false; show_helpers = false; - show_rulers = false; + show_rulers = true; show_guides = true; zoom = 1; grid_offset = Point2(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 19293360ed..3a443e1bf7 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1042,8 +1042,13 @@ void ScriptTextEditor::_edit_option(int p_op) { String delimiter = "#"; List<String> comment_delimiters; scr->get_language()->get_comment_delimiters(&comment_delimiters); - if (!comment_delimiters.empty()) { - delimiter = comment_delimiters.front()->get(); + + for (List<String>::Element *E = comment_delimiters.front(); E; E = E->next()) { + String script_delimiter = E->get(); + if (script_delimiter.find(" ") == -1) { + delimiter = script_delimiter; + break; + } } tx->begin_complex_operation(); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 390cbf727c..b855d2d4c4 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -4753,9 +4753,9 @@ VSplitContainer *SpatialEditor::get_shader_split() { return shader_split; } -HBoxContainer *SpatialEditor::get_palette_split() { +HSplitContainer *SpatialEditor::get_palette_split() { - return palette_split_container; + return palette_split; } void SpatialEditor::_request_gizmo(Object *p_obj) { @@ -5046,10 +5046,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { palette_split->set_v_size_flags(SIZE_EXPAND_FILL); vbc->add_child(palette_split); - palette_split_container = memnew(HBoxContainer); - palette_split_container->set_v_size_flags(SIZE_EXPAND_FILL); - palette_split->add_child(palette_split_container); - shader_split = memnew(VSplitContainer); shader_split->set_h_size_flags(SIZE_EXPAND_FILL); palette_split->add_child(shader_split); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index ab26a70f7f..0c2571017b 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -413,7 +413,6 @@ private: SpatialEditorViewport *viewports[VIEWPORTS_COUNT]; VSplitContainer *shader_split; HSplitContainer *palette_split; - HBoxContainer *palette_split_container; ///// @@ -608,7 +607,7 @@ public: void add_control_to_menu_panel(Control *p_control); VSplitContainer *get_shader_split(); - HBoxContainer *get_palette_split(); + HSplitContainer *get_palette_split(); Spatial *get_selected() { return selected; } diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 5cc81f156c..4d06342fe0 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -123,12 +123,14 @@ void TileMapEditor::_menu_option(int p_option) { return; undo_redo->create_action(TTR("Erase Selection")); + undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - _set_cell(Point2i(j, i), TileMap::INVALID_CELL, false, false, false, true); + _set_cell(Point2i(j, i), TileMap::INVALID_CELL, false, false, false); } } + undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); selection_active = false; @@ -171,7 +173,7 @@ void TileMapEditor::set_selected_tile(int p_tile) { } } -void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, bool p_flip_v, bool p_transpose, bool p_with_undo) { +void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, bool p_flip_v, bool p_transpose) { ERR_FAIL_COND(!node); @@ -184,17 +186,8 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose) return; //check that it's actually different - if (p_with_undo) { - - undo_redo->add_do_method(node, "set_cellv", Point2(p_pos), p_value, p_flip_h, p_flip_v, p_transpose); - undo_redo->add_do_method(node, "make_bitmask_area_dirty", Point2(p_pos)); - undo_redo->add_undo_method(node, "set_cellv", Point2(p_pos), prev_val, prev_flip_h, prev_flip_v, prev_transpose); - undo_redo->add_undo_method(node, "make_bitmask_area_dirty", Point2(p_pos)); - } else { - - node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose); - node->update_bitmask_area(Point2(p_pos)); - } + node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose); + node->update_bitmask_area(Point2(p_pos)); } void TileMapEditor::_text_entered(const String &p_text) { @@ -404,6 +397,7 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era } PoolVector<Vector2> points; + Vector<Vector2> non_preview_cache; int count = 0; int limit = 0; @@ -432,8 +426,10 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era bucket_cache_visited[loc] = true; bucket_cache.push_back(n); } else { - node->set_cellv(n, id, flip_h, flip_v, transpose); + if (non_preview_cache.find(n) >= 0) + continue; points.push_back(n); + non_preview_cache.push_back(n); } bucket_queue.push_back(Point2i(n.x, n.y + 1)); @@ -462,9 +458,10 @@ void TileMapEditor::_fill_points(const PoolVector<Vector2> p_points, const Dicti bool tr = p_op["transpose"]; for (int i = 0; i < len; i++) { - _set_cell(pr[i], id, xf, yf, tr); + node->make_bitmask_area_dirty(pr[i]); } + node->update_dirty_bitmask(); } void TileMapEditor::_erase_points(const PoolVector<Vector2> p_points) { @@ -730,10 +727,8 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { tool = TOOL_PAINTING; - paint_undo.clear(); - paint_undo[over_tile] = _get_op_from_cell(over_tile); - - _set_cell(over_tile, id, flip_h, flip_v, transpose); + undo_redo->create_action(TTR("Paint TileMap")); + undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); } } else if (tool == TOOL_PICKING) { @@ -754,15 +749,9 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { int id = get_selected_tile(); - if (id != TileMap::INVALID_CELL && paint_undo.size()) { - - undo_redo->create_action(TTR("Paint TileMap")); - for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { + if (id != TileMap::INVALID_CELL) { - Point2 p = E->key(); - undo_redo->add_do_method(node, "set_cellv", p, id, flip_h, flip_v, transpose); - undo_redo->add_undo_method(node, "set_cellv", p, E->get().idx, E->get().xf, E->get().yf, E->get().tr); - } + undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); paint_undo.clear(); @@ -774,10 +763,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { undo_redo->create_action(TTR("Line Draw")); + undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { - _set_cell(E->key(), id, flip_h, flip_v, transpose, true); + _set_cell(E->key(), id, flip_h, flip_v, transpose); } + undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); paint_undo.clear(); @@ -791,12 +782,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { undo_redo->create_action(TTR("Rectangle Paint")); + undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - _set_cell(Point2i(j, i), id, flip_h, flip_v, transpose, true); + _set_cell(Point2i(j, i), id, flip_h, flip_v, transpose); } } + undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); canvas_item_editor->update(); @@ -806,10 +799,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2 ofs = over_tile - rectangle.position; undo_redo->create_action(TTR("Duplicate")); + undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) { - _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose, true); + _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose); } + undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); copydata.clear(); @@ -822,28 +817,23 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } else if (tool == TOOL_BUCKET) { - Dictionary pop; - pop["id"] = node->get_cell(over_tile.x, over_tile.y); - pop["flip_h"] = node->is_cell_x_flipped(over_tile.x, over_tile.y); - pop["flip_v"] = node->is_cell_y_flipped(over_tile.x, over_tile.y); - pop["transpose"] = node->is_cell_transposed(over_tile.x, over_tile.y); - PoolVector<Vector2> points = _bucket_fill(over_tile); if (points.size() == 0) return false; + undo_redo->create_action(TTR("Bucket Fill")); + undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + Dictionary op; op["id"] = get_selected_tile(); op["flip_h"] = flip_h; op["flip_v"] = flip_v; op["transpose"] = transpose; - undo_redo->create_action(TTR("Bucket Fill")); - - undo_redo->add_do_method(this, "_fill_points", points, op); - undo_redo->add_undo_method(this, "_fill_points", points, pop); + _fill_points(points, op); + undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); // We want to keep the bucket-tool active @@ -885,6 +875,9 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2 local = node->world_to_map(xform_inv.xform(mb->get_position())); + undo_redo->create_action(TTR("Erase TileMap")); + undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + if (mb->get_shift()) { if (mb->get_control()) @@ -898,7 +891,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { tool = TOOL_ERASING; - paint_undo[local] = _get_op_from_cell(local); _set_cell(local, TileMap::INVALID_CELL); } @@ -908,18 +900,8 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } else { if (tool == TOOL_ERASING || tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { - if (paint_undo.size()) { - undo_redo->create_action(TTR("Erase TileMap")); - for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { - - Point2 p = E->key(); - undo_redo->add_do_method(node, "set_cellv", p, TileMap::INVALID_CELL, false, false, false); - undo_redo->add_undo_method(node, "set_cellv", p, E->get().idx, E->get().xf, E->get().yf, E->get().tr); - } - - undo_redo->commit_action(); - paint_undo.clear(); - } + undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); + undo_redo->commit_action(); if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { canvas_item_editor->update(); @@ -1006,10 +988,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2i pos = points[i]; - if (!paint_undo.has(pos)) { - paint_undo[pos] = _get_op_from_cell(pos); - } - _set_cell(pos, TileMap::INVALID_CELL); } diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index ce58cc9708..b5f2618576 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -167,7 +167,7 @@ class TileMapEditor : public VBoxContainer { void _update_palette(); void _menu_option(int p_option); - void _set_cell(const Point2i &p_pos, int p_value, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, bool p_with_undo = false); + void _set_cell(const Point2i &p_pos, int p_value, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false); void _canvas_mouse_enter(); void _canvas_mouse_exit(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index bbed7ff98d..eb2faa1ab1 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -1015,21 +1015,47 @@ void AutotileEditor::_on_tool_clicked(int p_tool) { tile_set->autotile_clear_bitmask_map(get_current_tile()); workspace->update(); } else if (p_tool == SHAPE_DELETE) { - if (!edited_collision_shape.is_null()) { - Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(get_current_tile()); - int index; - for (int i = 0; i < sd.size(); i++) { - if (sd[i].shape == edited_collision_shape) { - index = i; - break; - } - } - if (index >= 0) { - sd.remove(index); - tile_set->tile_set_shapes(get_current_tile(), sd); - edited_collision_shape.unref(); - current_shape.resize(0); - workspace->update(); + if (creating_shape) { + creating_shape = false; + current_shape.resize(0); + workspace->update(); + } else { + switch (edit_mode) { + case EDITMODE_COLLISION: { + if (!edited_collision_shape.is_null()) { + Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(get_current_tile()); + int index; + for (int i = 0; i < sd.size(); i++) { + if (sd[i].shape == edited_collision_shape) { + index = i; + break; + } + } + if (index >= 0) { + sd.remove(index); + tile_set->tile_set_shapes(get_current_tile(), sd); + edited_collision_shape = Ref<ConcavePolygonShape2D>(); + current_shape.resize(0); + workspace->update(); + } + } + } break; + case EDITMODE_NAVIGATION: { + if (!edited_navigation_shape.is_null()) { + tile_set->autotile_set_navigation_polygon(get_current_tile(), Ref<NavigationPolygon>(), edited_shape_coord); + edited_navigation_shape = Ref<NavigationPolygon>(); + current_shape.resize(0); + workspace->update(); + } + } break; + case EDITMODE_OCCLUSION: { + if (!edited_occlusion_shape.is_null()) { + tile_set->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); + edited_occlusion_shape = Ref<OccluderPolygon2D>(); + current_shape.resize(0); + workspace->update(); + } + } break; } } } else if (p_tool == ZOOM_OUT) { diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index d573a44cdd..6f9454be2c 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -3081,7 +3081,7 @@ void PropertyEditor::update_tree() { item->set_text(1, type + " ID: " + itos(id)); item->add_button(1, get_icon("EditResource", "EditorIcons")); } else { - item->set_text(1, "[Empty]"); + item->set_text(1, TTR("[Empty]")); } if (has_icon(p.hint_string, "EditorIcons")) { diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 7705e4e1b9..a1c1ec3351 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1853,7 +1853,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { inspect_scene_tree->connect("cell_selected", this, "_scene_tree_selected"); inspect_scene_tree->connect("item_collapsed", this, "_scene_tree_folded"); - auto_switch_remote_scene_tree = EDITOR_DEF("debugger/auto_switch_to_remote_scene_tree", true); + auto_switch_remote_scene_tree = EDITOR_DEF("debugger/auto_switch_to_remote_scene_tree", false); inspect_scene_tree_timeout = EDITOR_DEF("debugger/remote_scene_tree_refresh_interval", 1.0); inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2); inspected_object_id = 0; diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index 853761f689..fccd0c51aa 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -406,13 +406,13 @@ EditorSettingsDialog::EditorSettingsDialog() { shortcut_clear_button->connect("pressed", this, "_clear_shortcut_search_box"); shortcuts = memnew(Tree); - vbc->add_margin_child("Shortcut List:", shortcuts, true); + vbc->add_margin_child(TTR("Shortcut List:"), shortcuts, true); shortcuts->set_columns(2); shortcuts->set_hide_root(true); //shortcuts->set_hide_folding(true); shortcuts->set_column_titles_visible(true); - shortcuts->set_column_title(0, "Name"); - shortcuts->set_column_title(1, "Binding"); + shortcuts->set_column_title(0, TTR("Name")); + shortcuts->set_column_title(1, TTR("Binding")); shortcuts->connect("button_pressed", this, "_shortcut_button_pressed"); press_a_key = memnew(ConfirmationDialog); diff --git a/editor/translations/README.md b/editor/translations/README.md index 351bc9e2d1..f30f4e61fb 100644 --- a/editor/translations/README.md +++ b/editor/translations/README.md @@ -16,5 +16,8 @@ Link if you missed it: https://hosted.weblate.org/projects/godot-engine/godot ## Adding new languages If you want to translate for a language which is not featured yet on Weblate, -open an issue on this repo to ask that the language is added, or contact -Akien/@akien-mga directly on IRC (#godotengine channel on Freenode). +you can add it (when logged in) by clicking the "Start new translation" +button at the bottom of the page. + +Alternatively, you can use this +[direct link](https://hosted.weblate.org/new-lang/godot-engine/godot/). |