mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-27 15:35:21 +00:00
Add displayName property for language extensions (fix #3964)
The default language (en.ini) has a new "display_name" property, but probably we should remove it and transform the English language in an extension (just as the default Aseprite theme).
This commit is contained in:
parent
35e64ad2f3
commit
00b75a76a8
@ -2,6 +2,13 @@
|
||||
# Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
# Copyright (C) 2016-2018 David Capello
|
||||
|
||||
# Don't translate this string, in extensions you have to use the
|
||||
# "displayName" property of your "languages" item, see:
|
||||
#
|
||||
# https://aseprite.org/docs/extensions/languages/
|
||||
#
|
||||
display_name = English
|
||||
|
||||
[advanced_mode]
|
||||
title = Warning - Important
|
||||
description = You are going to enter in "Advanced Mode".
|
||||
|
@ -164,6 +164,19 @@ class OptionsWindow : public app::gen::Options {
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
class LangItem : public ListItem {
|
||||
public:
|
||||
LangItem(const LangInfo& langInfo)
|
||||
: ListItem(langInfo.displayName)
|
||||
, m_langInfo(langInfo) {
|
||||
}
|
||||
const std::string& langId() const {
|
||||
return m_langInfo.id;
|
||||
}
|
||||
private:
|
||||
LangInfo m_langInfo;
|
||||
};
|
||||
|
||||
class ExtensionItem : public ListItem {
|
||||
public:
|
||||
ExtensionItem(Extension* extension)
|
||||
@ -641,8 +654,9 @@ public:
|
||||
#endif
|
||||
|
||||
// Update language
|
||||
Strings::instance()->setCurrentLanguage(
|
||||
language()->getItemText(language()->getSelectedItemIndex()));
|
||||
if (auto item = dynamic_cast<const LangItem*>(language()->getSelectedItem())) {
|
||||
Strings::instance()->setCurrentLanguage(item->langId());
|
||||
}
|
||||
|
||||
m_globPref.timeline.firstFrame(firstFrame()->textInt());
|
||||
m_pref.general.showFullPath(showFullPath()->isSelected());
|
||||
@ -1285,11 +1299,12 @@ private:
|
||||
if (language()->getItemCount() > 0)
|
||||
return;
|
||||
|
||||
// Select current language by lang ID
|
||||
Strings* strings = Strings::instance();
|
||||
std::string curLang = strings->currentLanguage();
|
||||
for (const std::string& lang : strings->availableLanguages()) {
|
||||
int i = language()->addItem(lang);
|
||||
if (lang == curLang)
|
||||
for (const LangInfo& lang : strings->availableLanguages()) {
|
||||
int i = language()->addItem(new LangItem(lang));
|
||||
if (lang.id == curLang)
|
||||
language()->setSelectedItemIndex(i);
|
||||
}
|
||||
}
|
||||
|
@ -271,13 +271,17 @@ void Extension::addKeys(const std::string& id, const std::string& path)
|
||||
updateCategory(Category::Keys);
|
||||
}
|
||||
|
||||
void Extension::addLanguage(const std::string& id, const std::string& path)
|
||||
void Extension::addLanguage(const std::string& id,
|
||||
const std::string& path,
|
||||
const std::string& displayName)
|
||||
{
|
||||
m_languages[id] = path;
|
||||
m_languages[id] = LangInfo(id, path, displayName);
|
||||
updateCategory(Category::Languages);
|
||||
}
|
||||
|
||||
void Extension::addTheme(const std::string& id, const std::string& path, const std::string& variant)
|
||||
void Extension::addTheme(const std::string& id,
|
||||
const std::string& path,
|
||||
const std::string& variant)
|
||||
{
|
||||
m_themes[id] = ThemeInfo(path, variant);
|
||||
updateCategory(Category::Themes);
|
||||
@ -871,7 +875,7 @@ std::string Extensions::languagePath(const std::string& langId)
|
||||
|
||||
auto it = ext->languages().find(langId);
|
||||
if (it != ext->languages().end())
|
||||
return it->second;
|
||||
return it->second.path;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
@ -1147,15 +1151,19 @@ Extension* Extensions::loadExtension(const std::string& path,
|
||||
for (const auto& lang : languages.array_items()) {
|
||||
std::string langId = lang["id"].string_value();
|
||||
std::string langPath = lang["path"].string_value();
|
||||
std::string langDisplayName = lang["displayName"].string_value();
|
||||
|
||||
// The path must be always relative to the extension
|
||||
langPath = base::join_path(path, langPath);
|
||||
|
||||
LOG("EXT: New language id=%s path=%s\n",
|
||||
LOG("EXT: New language id=%s path=%s displayName=%s\n",
|
||||
langId.c_str(),
|
||||
langPath.c_str());
|
||||
langPath.c_str(),
|
||||
langDisplayName.c_str());
|
||||
|
||||
extension->addLanguage(langId, langPath);
|
||||
extension->addLanguage(langId,
|
||||
langPath,
|
||||
langDisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define APP_EXTENSIONS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/i18n/lang_info.h"
|
||||
#include "obs/signal.h"
|
||||
#include "render/dithering_matrix.h"
|
||||
|
||||
@ -80,6 +81,7 @@ namespace app {
|
||||
, variant(variant) { }
|
||||
};
|
||||
|
||||
using Languages = std::map<std::string, LangInfo>;
|
||||
using Themes = std::map<std::string, ThemeInfo>;
|
||||
using DitheringMatrices = std::map<std::string, DitheringMatrixInfo>;
|
||||
|
||||
@ -101,13 +103,17 @@ namespace app {
|
||||
const Category category() const { return m_category; }
|
||||
|
||||
const ExtensionItems& keys() const { return m_keys; }
|
||||
const ExtensionItems& languages() const { return m_languages; }
|
||||
const Languages& languages() const { return m_languages; }
|
||||
const Themes& themes() const { return m_themes; }
|
||||
const ExtensionItems& palettes() const { return m_palettes; }
|
||||
|
||||
void addKeys(const std::string& id, const std::string& path);
|
||||
void addLanguage(const std::string& id, const std::string& path);
|
||||
void addTheme(const std::string& id, const std::string& path, const std::string& variant);
|
||||
void addLanguage(const std::string& id,
|
||||
const std::string& path,
|
||||
const std::string& displayName);
|
||||
void addTheme(const std::string& id,
|
||||
const std::string& path,
|
||||
const std::string& variant);
|
||||
void addPalette(const std::string& id, const std::string& path);
|
||||
void addDitheringMatrix(const std::string& id,
|
||||
const std::string& path,
|
||||
@ -152,7 +158,7 @@ namespace app {
|
||||
#endif
|
||||
|
||||
ExtensionItems m_keys;
|
||||
ExtensionItems m_languages;
|
||||
Languages m_languages;
|
||||
Themes m_themes;
|
||||
ExtensionItems m_palettes;
|
||||
DitheringMatrices m_ditheringMatrices;
|
||||
|
36
src/app/i18n/lang_info.h
Normal file
36
src/app/i18n/lang_info.h
Normal file
@ -0,0 +1,36 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_I18N_LANG_INFO_INCLUDED
|
||||
#define APP_I18N_LANG_INFO_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
|
||||
struct LangInfo {
|
||||
std::string id;
|
||||
std::string path;
|
||||
std::string displayName;
|
||||
|
||||
LangInfo() = default;
|
||||
LangInfo(const std::string& id,
|
||||
const std::string& path,
|
||||
const std::string& displayName)
|
||||
: id(id)
|
||||
, path(path)
|
||||
, displayName(displayName.empty() ? id: displayName) {
|
||||
}
|
||||
|
||||
bool operator<(const LangInfo& other) const {
|
||||
return id < other.id;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -19,6 +20,8 @@
|
||||
#include "base/fs.h"
|
||||
#include "cfg/cfg.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace app {
|
||||
|
||||
static Strings* singleton = nullptr;
|
||||
@ -46,20 +49,29 @@ Strings::Strings(Preferences& pref,
|
||||
loadLanguage(currentLanguage());
|
||||
}
|
||||
|
||||
std::set<std::string> Strings::availableLanguages() const
|
||||
std::set<LangInfo> Strings::availableLanguages() const
|
||||
{
|
||||
std::set<std::string> result;
|
||||
std::set<LangInfo> result;
|
||||
|
||||
// Add languages in data/strings/
|
||||
ResourceFinder rf;
|
||||
rf.includeDataDir("strings");
|
||||
while (rf.next()) {
|
||||
if (!base::is_directory(rf.filename()))
|
||||
const std::string stringsPath = rf.filename();
|
||||
if (!base::is_directory(stringsPath))
|
||||
continue;
|
||||
|
||||
for (const auto& fn : base::list_files(rf.filename())) {
|
||||
for (const auto& fn : base::list_files(stringsPath)) {
|
||||
const std::string langId = base::get_file_title(fn);
|
||||
result.insert(langId);
|
||||
std::string path = base::join_path(stringsPath, fn);
|
||||
std::string displayName = langId;
|
||||
|
||||
// Load display name
|
||||
cfg::CfgFile cfg;
|
||||
if (cfg.load(path))
|
||||
displayName = cfg.getValue("", "display_name", displayName.c_str());
|
||||
|
||||
result.insert(LangInfo(langId, path, displayName));
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,12 +79,17 @@ std::set<std::string> Strings::availableLanguages() const
|
||||
for (const auto& ext : m_exts) {
|
||||
if (ext->isEnabled() &&
|
||||
ext->hasLanguages()) {
|
||||
for (const auto& langId : ext->languages())
|
||||
result.insert(langId.first);
|
||||
for (const auto& lang : ext->languages())
|
||||
result.insert(lang.second);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(result.find(kDefLanguage) != result.end());
|
||||
// Check that the default language exists.
|
||||
ASSERT(std::find_if(result.begin(), result.end(),
|
||||
[](const LangInfo& li){
|
||||
return li.id == kDefLanguage;
|
||||
}) != result.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -8,14 +9,14 @@
|
||||
#define APP_I18N_STRINGS_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/i18n/lang_info.h"
|
||||
#include "obs/signal.h"
|
||||
#include "strings.ini.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "obs/signal.h"
|
||||
|
||||
#include "strings.ini.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class Preferences;
|
||||
@ -30,7 +31,7 @@ namespace app {
|
||||
|
||||
const std::string& translate(const char* id) const;
|
||||
|
||||
std::set<std::string> availableLanguages() const;
|
||||
std::set<LangInfo> availableLanguages() const;
|
||||
std::string currentLanguage() const;
|
||||
void setCurrentLanguage(const std::string& langId);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Config Library
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2014-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -88,7 +88,7 @@ public:
|
||||
m_ini.Delete(section, nullptr, true);
|
||||
}
|
||||
|
||||
void load(const std::string& filename) {
|
||||
bool load(const std::string& filename) {
|
||||
m_filename = filename;
|
||||
|
||||
base::FileHandle file(base::open_file(m_filename, "rb"));
|
||||
@ -98,8 +98,10 @@ public:
|
||||
if (err != SI_OK) {
|
||||
LOG(ERROR, "CFG: Error %d loading configuration from %s\n",
|
||||
(int)err, m_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void save() {
|
||||
@ -193,9 +195,9 @@ void CfgFile::deleteSection(const char* section)
|
||||
m_impl->deleteSection(section);
|
||||
}
|
||||
|
||||
void CfgFile::load(const std::string& filename)
|
||||
bool CfgFile::load(const std::string& filename)
|
||||
{
|
||||
m_impl->load(filename);
|
||||
return m_impl->load(filename);
|
||||
}
|
||||
|
||||
void CfgFile::save()
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Config Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2014-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -37,7 +37,7 @@ namespace cfg {
|
||||
void deleteValue(const char* section, const char* name);
|
||||
void deleteSection(const char* section);
|
||||
|
||||
void load(const std::string& filename);
|
||||
bool load(const std::string& filename);
|
||||
void save();
|
||||
|
||||
private:
|
||||
|
Loading…
x
Reference in New Issue
Block a user