Поддержка локализации из GoogleDocs

GoogleDocs (GoogleSheets) могут являться источниками данных для локализации, настроек или игрового баланса. Для их импорта и разбора существует множество пакетов, но все эти решения достаточно объемные и ориентированы исключительно на работу в редакторе Unity. Что, если нам хочется что-то подправить на лету и не ждать несколько минут, пока пересоберется новый билд с новыми данными?

Разбор данных

Самым простым, оптимальным по размеру и поддерживаемым всеми табличными редакторами является CSV. Данные в нем представлены в виде строк, составленных из значений ячеек, разделенных запятыми.
Формат поддерживает UTF8, кавычки и запятые в качестве значений и не имеет дополнительного мусора в виде обязательных отступов, скобок и т.д.

Пакет Leopotam.Serialization.Csv обеспечивает поддержку разбора “сырых” CSV данных в коллекции, с которыми уже можно работать из кода. Допустим, у нас есть следующая таблица:

111213
212223

Разбор в таблицу

Данные могут быть разобраны в таблицу:

1
2
3
4
5
6
7
8
9
10
11
12
string csv = "...csv данные...";
// Нужно ли преобразовывать пару символов "\n" в реальный перевод строки.
bool normalizeNewLines = true;
(List<List<string>> table, bool ok) = CsvReader.ParseTable (csv, normalizeNewLines);
if (!ok) {
// Произошла ошибка - некорректный формат.
return;
}

// table[0][0] == "11"
// table[0][2] == "13"
// table[1][0] == "21"

Этот вариант может использоваться для работы с данными, когда порядок важен, но нет уникального ключа для доступа к каждой строке.

Разбор в словарь значений

Данные могут быть разобраны в набор пар “Ключ/Значение” - первый столбец считается ключом, второй значением, остальные столбцы игнорируются:

1
2
3
4
5
6
7
8
9
10
11
string csv = "...csv данные...";
// Нужно ли преобразовывать пару символов "\n" в реальный перевод строки.
bool normalizeNewLines = true;
(Dictionary<string, string> dict, bool ok) = CsvReader.ParseKeyedValues (csv, normalizeNewLines);
if (!ok) {
// Произошла ошибка - некорректный формат.
return;
}

// dict["11"] == "12"
// dict["21"] == "22"

Этот вариант может быть использован для хранения настроек, когда первый столбец является именем настройки, а второй - ее значением.

Разбор в словарь списков

Данные могут быть разобраны в набор пар “Ключ/Значение” - первый столбец считается ключом, второй и последующие являются списком-значением:

1
2
3
4
5
6
7
8
9
10
11
12
string csv = "...csv данные...";
// Нужно ли преобразовывать пару символов "\n" в реальный перевод строки.
bool normalizeNewLines = true;
(Dictionary<string, List<string>> dict, bool ok) = CsvReader.ParseKeyedLists (csv, normalizeNewLines);
if (!ok) {
// Произошла ошибка - некорректный формат.
return;
}

// dict["11"][0] == "12"
// dict["11"][1] == "13"
// dict["21"][1] == "23"

Этот вариант может использоваться для локализации или для работы с любыми данными, где необходима адресация в виде имени-ключа к коллекции столбцов.

Локализация

Используя предыдущий пакет, мы можем загружать данные и интерпретировать их как локализацию, где первый столбец является ключом, а остальные столбцы содержат переводы на разные языки. Первая строчка является заголовком и содержит названия языков:

KEYRussianEnglish
titleЗаголовокTitle
descОписаниеDescription

Пакет Leopotam.Localization обеспечивает разбор CSV-данных и поддержку получения локализованных данных на основе текущего языка и Категории. Категория - это по сути отдельная страница в GoogleSheets, которая никак не пересекается с другими страницами и может содержать ключи с такими же именами. Отдельным требованием пакета является именование строки заголовка ключом KEY.

Инициализация данных

1
2
3
4
5
6
7
8
9
10
11
// Стартовый язык.
string csv = "...csv-данные-локализации...";
string lang = "Russian";
// Логическое имя категории.
string category = "Items";
Localization loc = new Localization (lang);
bool ok = loc.AddSource (csv, category);
if (!ok) {
// Что-то пошло не так - некорректный формат или отсутствующий заголовок.
return;
}

Запрос переводов

1
2
3
4
5
6
7
8
9
// Запрос локализации для текущего языка.
(string val1, bool ok1) = loc.Get ("title", category);
// Запрос локализации для указанного языка.
(string val2, bool ok2) = loc.GetFor ("title", category, "English");

// val1 = Заголовок - значение.
// ok1 = true - успех операции.
// val2 = Title - значение.
// ok2 = true - успех операции.

Если строки с указанным ключом не будет в наличии - в качестве перевода вернется сам ключ.

Загрузка данных из GoogleDocs

CSV-данные могут храниться в виде текстовых ресурсов в проекте, так и находиться на удаленном сервере, например, GoogleDocs. Их загрузку в рантайме обеспечивает пакет Leopotam.GoogleDocs.Unity - для работы достаточно скопировать адрес из строки браузера и указать имя страницы:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Прямая ссылка на документ.
string url = "https://docs.google.com/spreadsheets/d/1_xxxxxxx-yyyy/edit#gid=0";
// Имя страницы.
string page = "Items";
(string csv, string err) = await GoogleDocsLoader.LoadCsvPage (url, page);
if (err != null) {
// Что-то пошло не так, в err текст ошибки.
return;
}
// Можно работать со строкой csv-данных. Например, загрузить локализацию.
Localization loc = new Localization ("Russian");
bool ok = loc.AddSource (csv, page);
if (!ok) {
// Что-то пошло не так - некорректный формат или отсутствующий заголовок.
return;
}
int itemId = 1234;
string name = loc.Get ($"item.{itemId}.name", page);
Актуальные версии пакетов доступны в закрытом discord-сервере для vk/boosty-подписчиков.
Оформить подписку можно здесь: