是否可以将 {} 替换为本地化的退格键

Is it possible to replace {} with a backspace for localizations

我们正在使用 flutter easy localizations 并且我们有使用参数的文本。例如,我们的 localizations 文档中有一个字符串,如下所示,

{
  "someAppText":"This is {} app text {}."
}

但有时参数会为空。这将导致以下文本

This is[SPACE][SPACE]app text[SPACE].

空格还在的地方。是否可以在没有参数的情况下退格?

首先,使用plural怎么样?听起来您想为不同类型的数据使用不同的文本。当 arg 为空时,我没有想出其他例子,所以如果不是你的情况,你能举一个具体的例子吗?

其次,您可以按如下方式进行简单的字符串操作(伪代码)。该代码仅演示了最简单的情况(使其简短),但扩展到完整情况是微不足道的。

String myTranslate(String formatString, List<String> args) {
  const EMPTY_MARKER = 'EMPTY_MARKER';
  final transformedArgs = args.map((arg) => arg.isEmpty ? EMPTY_MARKER : arg).toList();
  final rawString = formatString.tr(transformedArgs);
  return rawString.replaceAll(' $EMPTY_MARKER', '');
}

那么在你的例子中,它会输出:This is[SPACE]app text.

我们不能在 JSON 文件中添加任何方法,只能使用它的简单 map data

所以

解决方案将在 JSON 中使用特殊字符串,以便能够在 运行 时间内检测和处理它们

假设 JSON 会有这个

{
  "someAppText": "This is #VAR01 app text #VAR02."
}

然后让我们创建另一个class,它有处理这些特殊词的方法,他们应该检测它们,并用其他动态输入替换它们

所以

    class JSONWorkAround {

  /// A - need to define the string pattern we are using in the string which I assumed to look like '#VAR00'
  /// let's call them jsonVariables
  /// NOTE : if you would like to name them #VAR000 ,, then regExp would be r'#VAR...'
  static RegExp regExp = RegExp(r'#VAR..');

  /// B - let's make a tracker for any word that matches this regExp in any input string
  static List<String> _searchJSONVariablesByRegExp({@required String text, @required RegExp regExp}){

    List<String> _strings;

    /// always check if not null before we do stuff to avoid errors and save performance
    if (text != null){
      _strings = regExp.allMatches(text).map((m) => m.group(0)).toList();



    }

    return _strings;
  }

  /// C - let's make the tracker specifically for those JSONVariables from a string received from the JSON doc "let's call it rawString"
  static List<String> _searchJSONVariablesFromRawString({@required String rawString}){
    final List<String> _jsonVariables = _searchJSONVariablesByRegExp(text: rawString, regExp: regExp);
    return _jsonVariables;
  }

  /// E - let's see what to do with the search result
  static List<SpecialWord> _processJSONVariables(List<String> jsonVariables){

    List<SpecialWord> _outputSpecialWords = <SpecialWord>[];

    /// so w notice we will need to process each one alone,, so we loop them out
    if(jsonVariables != null && jsonVariables.isNotEmpty){

      jsonVariables.forEach((jsonVariable) {

        /// we should receive a substitute string instead of that #VAR00 special string,, so ..
        /// actually we need to receive a string that is accompanied with its cipher special thing to be able to go back to the sentence and change it,,, like using this special #VAR00 thing as ID
        /// and I don't like map<String, dynamic> but I would rather create a model class ,, will be written down there at the end of this class
        final SpecialWord _substitute = _processSingleJSONVariable(jsonVariable: jsonVariable);

        /// then we add them to the output List
        if (_substitute != null){
          _outputSpecialWords.add(_substitute);
        }
      });


    }

    return _outputSpecialWords;
  }

  /// D - need to receive both the substitute and its (JSONSpecialVariable / ID) to be able to search for it and process it in the original string
  static SpecialWord _processSingleJSONVariable({@required String jsonVariable}){

    final SpecialWord _substitute = SpecialWord.getSpecialWordFromAllSpecialWordsByID(jsonVariable);

    return _substitute;
  }

  /// F - finally after receiving the substitutes inside a list<SpecialWord>,, we get get back the original String with the substitutes
  static String processJSONStringThatContainsThoseSpecialVariables(String rawString){

    /// this has to initialize with the initial raw string value to be processed
    String _processedString = rawString;

    final List<String> _jsonVariables = _searchJSONVariablesFromRawString(rawString: rawString);

    if (_jsonVariables != null && _jsonVariables.isNotEmpty){

      final List<SpecialWord> _specialWords = _processJSONVariables(_jsonVariables);

      /// then we need to change each jsonVariable with its substitute
      _specialWords.forEach((specialWord) {

        _processedString = _replaceSubStringWith(
            subStringToReplace: specialWord.id,
            replacement: specialWord.substitute,
            input: _processedString,
        );

      });
    }

    return _processedString;
  }

  /// G - a text replacing method to easily replace a given subString from a string with another value
  static String _replaceSubStringWith({@required String subStringToReplace, @required String replacement, @required String input}){
    final String _output = input.replaceAll(subStringToReplace, replacement);
    return _output;
  }

}

class SpecialWord{
  final String id;
  final String substitute; // you can change this to be more complex to adapt to many languages or other things

  const SpecialWord({
    @required this.id,
    @required this.substitute,
});

  /// lets create a list of constants that u may change in future and call from db or wherever
  static const List<SpecialWord> _allSpecialWords = const <SpecialWord>[

    SpecialWord(id: '#VAR01', substitute: 'Baby'),
    SpecialWord(id: '#VAR02', substitute: 'Cool'),
    SpecialWord(id: '#VAR03', substitute: 'You got the Idea'),

  ];

  /// I like to pamper myself with super quick methods to be clean and organized
  static SpecialWord getSpecialWordFromAllSpecialWordsByID(String id){
    SpecialWord _foundWord;

    if (id != null){

      _foundWord = _allSpecialWords.firstWhere((word) => word.id == id, orElse: () => null);

    }

    return _foundWord;
  }

}

然后让我们进行一些方法测试,以确保此样板在工程代码上的安全性

  test("Testing JSON Variables work around idea", () async {

    String _rawString = "This is #VAR01 app text #VAR02.";

    String _processedString = JSONWorkAround.processJSONStringThatContainsThoseSpecialVariables(_rawString);

    String _expectation = "This is Baby app text Cool.";

    expect(_processedString, _expectation);

  });

但现在您可能会问自己,这值得吗,我是否过度设计了东西,有没有更明智的解决方案?,也许只是将每个案例保存在 json从一开始,我不知道,

恐怕我的解决方案过于复杂了,但它的效果很好

我不确定我是否理解您的问题。但请尝试以下操作。

添加两个翻译,一个用于空参数 someAppTextEmpty,一个用于常规参数 someAppText

{
  "someAppText": "This is {} app text {}.",
  "someAppTextEmpty": "This is the alternative app text."
}

然后检查参数是否为空以获得正确的翻译键:

final String translationKey = argument.isNotEmpty
  ? 'someAppText' : 'someAppTextEmpty';

然后像这样将变量translationKey传递给easy_localization的翻译函数:

final String title = tr(translationKey);

// Or

Text(translationKey).tr();

// Or

translationKey.tr();

没有

有或没有 easy_localization,Dart 中的后退 space 字符在字符串中取 1 space 而不是删除 1 space。这是我通过反复试验得出的结论。

我的建议:

  1. 创建一个名为 BACKSPACE 的字符串,其中包含一个从未使用过的值,以 space 开头,例如:

    final String BACKSPACE = 'NEVER_USED_VALUE';
    
  2. 适当时,将 BACKSPACE 分配给 value1 和 value2 而不是空字符串。

  3. 然后,这样做:

    'someAppText'.tr(value1, value2).replaceAll(' ' + BACKSPACE, '');