Alert Source Discuss
🚧 Stagnant Standards Track: ERC

ERC-1444: 使用信号到文本的本地化消息

Authors Brooklyn Zelenka (@expede), Jennifer Cooper (@jenncoop)
Created 2018-09-23
Discussion Link https://ethereum-magicians.org/t/eip-1444-localized-messaging-with-signal-to-text/

简单总结

一种将机器码转换为任何语言和措辞的人类可读文本的方法。

摘要

一种链上系统,通过将机器高效的代码转换为任何语言或措辞的人类可读字符串来提供用户反馈。该系统不强制规定语言列表,而是让用户创建、共享和使用他们选择的本地化文本。

动机

在许多情况下,最终用户需要来自智能合约的反馈或指导。直接公开数字代码不会带来良好的 UX 或 DX。如果以太坊要成为一个真正全球性的系统,可以被专家和普通人使用,那么就需要提供关于交易期间发生的事情的反馈系统,并且尽可能使用多种语言。

返回硬编码的字符串(通常是英语)只能服务于全球人口的一小部分。本标准提出了一种方法,允许用户创建、注册、共享和使用去中心化的翻译集合,从而实现更丰富、更具文化和语言多样性的消息传递。

有几种机器高效的方式来表示意图、状态、状态转换和其他语义信号,包括布尔值、枚举和 ERC-1066 代码。通过为这些信号提供人类可读的消息,开发人员可以通过返回更容易消费且具有更多上下文的信息(例如 revert)来增强开发体验。通过提供可以传播到 UI 的文本来增强最终用户体验。

规范

合约架构

两种类型的合约:LocalizationPreferencesLocalization

LocalizationPreferences 合约充当 tx.origin 的代理。

                                                                   +--------------+
                                                                   |              |
                                                          +------> | Localization |
                                                          |        |              |
                                                          |        +--------------+
                                                          |
                                                          |
+-----------+          +-------------------------+        |        +--------------+
|           |          |                         | <------+        |              |
| Requestor | <------> | LocalizationPreferences | <-------------> | Localization |
|           |          |                         | <------+        |              |
+-----------+          +-------------------------+        |        +--------------+
                                                          |
                                                          |
                                                          |        +--------------+
                                                          |        |              |
                                                          +------> | Localization |
                                                                   |              |
                                                                   +--------------+

Localization

一个合约,其中包含代码到其文本表示的简单映射。

interface Localization {
  function textFor(bytes32 _code) external view returns (string _text);
}

textFor

获取本地化的文本表示。

function textFor(bytes32 _code) external view returns (string _text);

LocalizationPreferences

一个代理合约,允许用户设置他们首选的 Localization。文本查找被委托给用户首选的合约。

必须提供一个填充了所有键的后备 Localization。如果用户指定的 Localization 没有显式设置本地化(即 textFor 返回 ""),则 LocalizationPreferences 必须重新委托给后备 Localization

interface LocalizationPreferences {
  function set(Localization _localization) external returns (bool);
  function textFor(bytes32 _code) external view returns (bool _wasFound, string _text);
}

set

注册用户首选的 Localization。注册用户应被视为 tx.origin

function set(Localization _localization) external;

textFor

检索在用户首选的 Localization 合约中找到的代码的文本。

第一个返回值(bool _wasFound)表示文本是否可从该 Localization 获得,或者是否使用了后备。如果在此上下文中使用了后备,则 textFor 的第一个返回值必须设置为 false,否则为 true

function textFor(bytes32 _code) external view returns (bool _wasFound, string _text);

字符串格式

所有字符串必须编码为 UTF-8

"Špeĉiäl chârãçtérs are permitted"
"As are non-Latin characters: アルミ缶の上にあるみかん。"
"Emoji are legal: 🙈🙉🙊🎉"
"Feel free to be creative: (ノ◕ヮ◕)ノ*:・゚✧"

模板

允许使用模板字符串,并且必须遵循 ANSI C printf 约定。

"Satoshi's true identity is %s"

具有 2 个或更多参数的文本应使用 POSIX 参数字段扩展。

"Knock knock. Who's there? %1$s. %1$s who? %2$s!"

理由

bytes32

bytes32 非常高效,因为它是 EVM 的基本字长。 鉴于元素的数量巨大(card(A) > 1.1579 × 1077),它可以嵌入几乎任何实际的信号、枚举或状态。 如果应用程序的密钥长度超过 bytes32,则哈希该长密钥可以将该值映射到正确的宽度。

使用宽度小于 bytes32 的数据类型(例如 ERC-1066 中的 bytes1)的设计可以直接嵌入到更大的宽度中。 这是较小集合到较大集合的简单的一对一映射。

本地与全局和单例

此规范选择不_强制_使用单个全局注册表,而是允许任何合约和用例部署他们自己的系统。 这允许更大的灵活性,并且不限制社区选择使用单例 LocalizationPreference 合约来处理常见用例、在不同的代理之间共享 Localization 、在 Localization 之间委派翻译等等。

对于约定好的单例有很多实际用途。 例如,翻译旨在相当通用并直接集成到更广泛生态系统(钱包、框架、调试器等)中的代码将需要一个 LocalizationPreference

与其为不同的用例和代码分散几个 LocalizationPreference,不如想象一个全局的“注册表注册表”。 虽然这种方法允许统一查找所有用例中的所有翻译,但它与权力下放和自由的精神背道而驰。 这样的系统还会增加查找的复杂性,将正确获取代码的责任放在首位(或增加可升级合约的开销),并且需要考虑使用“统一”或集中式编号系统的用例冲突。 此外,查找应该是轻量级的(尤其是在查找还原文本等情况下)。

由于这些原因,本规范选择了更加去中心化、轻量级、自由的方法,但代价是链上可发现性。 仍然可以编译注册表,但很难强制执行,并且超出本规范的范围。

链下存储

另一种非常可行的替代方法是将文本存储在链下,并在链上放置一个指向翻译的指针,并发出或返回一个 bytes32 代码,供另一方执行查找。 很难保证链下资源可用,并且需要来自 Web 服务器等其他系统的协调才能完成代码到文本的匹配。 这也不与 revert 消息兼容。

ASCII 与 UTF-8 与 UTF-16

在撰写本文时,UTF-8 是使用最广泛的编码。 它包含 ASCII 的直接嵌入,同时为大多数自然语言、表情符号和特殊字符提供字符。

请参阅 UTF-8 Everywhere Manifesto 了解更多信息。

何时未找到文本

向请求者返回空字符串完全违背了本地化系统的目的。 处理丢失文本的两个选项是:

  1. 以首选语言显示的通用“未找到文本”消息
  2. 用另一种语言显示实际消息

通用选项

此设计选择不使用通用后备文本。 除了可能联系 Localization 维护者(如果甚至存在维护者并且更新是可能的)之外,它没有向用户提供任何有用的信息。

后备选项

本提案中概述的设计是以常用语言(例如英语或普通话)提供文本。 首先,如果用户尚未设置首选项,则这是将路由到的语言。 其次,用户很有可能对该语言有一定的熟练程度,或者至少能够使用自动翻译服务。

通过 textFor 的第一个返回字段布尔值来了解文本是否已后退 much 比事后尝试进行语言检测要简单得多。 此信息对于某些 UI 案例很有用。 例如,可能需要解释为什么本地化会回退。

去中心化的文本众包

为了使以太坊获得大规模采用,用户必须能够以他们最舒服的语言、措辞和详细程度与其进行交互。 此 EIP 没有像传统的集中式应用程序那样强加一组固定的翻译,而是提供了一种供任何人创建、管理和使用翻译的方法。 这使人群能够提供在文化和语言上多样化的消息传递,从而导致更广泛和更分散的信息访问。

printf 样式的格式字符串

C 样式的 printf 模板已经成为事实上的标准一段时间了。 它们在大多数语言中具有广泛的兼容性(无论是在标准库中还是在第三方库中)。 这使得消费程序可以更轻松地以较低的开发开销来插入字符串。

参数字段

POSIX 参数字段扩展很重要,因为语言不共享共同的词序。 参数字段支持在不同的本地化中重用和重新排列参数。

("%1$s is an element with the atomic number %2$d!", "Mercury", 80);
// => "Mercury is an element with the atomic number 80!"

简化的本地化

本地化文本不需要使用所有参数,并且可以简单地忽略值。 这对于不向用户公开更多技术信息可能很有用,否则用户会觉得这些信息令人困惑。

#!/usr/bin/env ruby

sprintf("%1$s é um elemento", "Mercurio", 80)
# => "Mercurio é um elemento"
#!/usr/bin/env clojure

(format "Element #%2$s" "Mercury" 80)
;; => Element #80

插值策略

请注意,强烈建议按_原样_返回模板字符串,并将参数作为多个返回值或 event 中的字段,并将实际插值留待链下完成。

event AtomMessage {
  bytes32 templateCode;
  bytes32 atomCode;
  uint256 atomicNumber;
}
#!/usr/bin/env node

var printf = require('printf');

const { returnValues: { templateCode, atomCode, atomicNumber } } = eventResponse;

const template = await AppText.textFor(templateCode);
// => "%1$s ist ein Element mit der Ordnungszahl %2$d!"

const atomName = await PeriodicTableText.textFor(atomCode);
// => "Merkur"

printf(template, atomName, 80);
// => "Merkur ist ein Element mit der Ordnungszahl 80!"

未指定的行为

本规范未指定:

  • 对默认 Localization 的公共或私有访问
  • 谁可以设置文本
    • 部署者
    • onlyOwner
    • 任何人
    • 列入白名单的用户
    • 等等
  • 何时设置文本
    • constructor
    • 任何时候
    • 写入空插槽,但不覆盖现有文本
    • 等等

这些是有意保持开放的。 这些情况有很多,并且限制任何一个都完全超出了本提案的范围。

实施

pragma solidity ^0.4.25;

contract Localization {
  mapping(bytes32 => string) private dictionary_;

  constructor() public {}

  // Currently overwrites anything
  // 当前覆盖任何内容
  function set(bytes32 _code, string _message) external {
    dictionary_[_code] = _message;
  }

  function textFor(bytes32 _code) external view returns (string _message) {
    return dictionary_[_code];
  }
}

contract LocalizationPreference {
  mapping(address => Localization) private registry_;
  Localization public defaultLocalization;

  bytes32 private empty_ = keccak256(abi.encodePacked(""));

  constructor(Localization _defaultLocalization) public {
    defaultLocalization = _defaultLocalization;
  }

  function set(Localization _localization) external returns (bool) {
    registry_[tx.origin] = _localization;
    return true;
  }

  function get(bytes32 _code) external view returns (bool, string) {
    return get(_code, tx.origin);
  }

  // Primarily for testing
  // 主要用于测试
  function get(bytes32 _code, address _who) public view returns (bool, string) {
    string memory text = getLocalizationFor(_who).textFor(_code);

    if (keccak256(abi.encodePacked(text)) != empty_) {
      return (true, text);
    } else {
      return (false, defaultLocalization.textFor(_code));
    }
  }

  function getLocalizationFor(address _who) internal view returns (Localization) {
    if (Localization(registry_[_who]) == Localization(0)) {
      return Localization(defaultLocalization);
    } else {
      return Localization(registry_[tx.origin]);
    }
  }
}

版权

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Brooklyn Zelenka (@expede), Jennifer Cooper (@jenncoop), "ERC-1444: 使用信号到文本的本地化消息 [DRAFT]," Ethereum Improvement Proposals, no. 1444, September 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1444.