• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import {
17  isNull,
18  getValue,
19  Log
20} from '../../../utils/index';
21
22interface I18nConstructor {
23  new(options: object): I18n;
24}
25
26export interface I18nInterface {
27  instance?: { I18n: I18nConstructor };
28}
29
30interface VMInterface {
31  $t: Function;
32  $tc: Function;
33  _i18n: Function;
34}
35
36const instances = {};
37
38/**
39 * This class provide internationalization support.
40 */
41class I18n {
42  public locale: string;
43  public messages: any;
44
45  constructor(options) {
46    this.locale = options.locale || language;
47    this.messages = options.messages;
48  }
49
50  /**
51   * Provide the '$t' method to import simple resources.
52   * @param {string} path - The path of language resources which to be translated.
53   * @param {*} [params] - The values of placeholder.
54   * @return {*} The translated result.
55   */
56  public $t(path: string, params?: any): any {
57    if (typeof path !== 'string') {
58      Log.warn(`Invalid parameter type: The type of 'path' should be string, not ${typeof path}.`);
59      return;
60    }
61    if (!this._hasMessage(this.messages)) {
62      return path;
63    }
64    let value = this._getMessage(this.messages, path);
65    if (isNull(value)) {
66      return path;
67    }
68    if (Object.prototype.toString.call(value) === '[object Object]' ||
69      Object.prototype.toString.call(value) === '[object Array]') {
70      return value;
71    }
72    value = this._translate(path, value, params);
73    return value;
74  }
75
76  /**
77   * Provide the '$tc' method to import singular and plural resources.
78   * @param {string} path - The path of language resources which to be translated.
79   * @param {number} [count] - The number which to be translated.
80   * @return {*} The translated result.
81   */
82  public $tc(path: string, count?: number): any {
83    if (typeof path !== 'string') {
84      Log.warn(`Invalid parameter type: The type of 'path' should be string, not ${typeof path}.`);
85      return;
86    }
87    if (typeof count !== 'number' && !isNull(count)) {
88      Log.warn(`Invalid parameter type: The type of 'count' should be number, not ${typeof count}.`);
89      return;
90    }
91    if (!this._hasMessage(this.messages)) {
92      return path;
93    }
94    let value = this._getMessage(this.messages, path);
95    if (isNull(value)) {
96      return path;
97    }
98    if (isNull(count)) {
99      count = 1;
100    }
101    value = this._getChoice(count, path, value);
102    value = this._translate(path, value, count);
103    return value;
104  }
105
106  /**
107  * Extend _i18n to Vm.
108  * @param {VMInterface} Vm - The Vm.
109  */
110  public extend(Vm: VMInterface): void {
111    Object.defineProperty(Vm, '_i18n', {
112      configurable: true,
113      enumerable: true,
114      get: function proxyGetter() {
115        return this.i18n ? this.i18n : global.aceapp.i18n;
116      }
117    });
118    Vm.$t = function(path, params) {
119      const i18n = this._i18n;
120      return i18n.$t(path, params);
121    };
122    Vm.$tc = function(path, count) {
123      const i18n = this._i18n;
124      return i18n.$tc(path, count);
125    };
126  }
127
128  private _hasMessage(message: object[]): boolean {
129    if (!message || message.length === 0) {
130      Log.debug('I18n message is null.');
131      return false;
132    }
133    return true;
134  }
135
136  private _getMessage(messages: any[], path: string): any {
137    for (const i in messages) {
138      const value = getValue(path, messages[i]);
139      if (!isNull(value)) {
140        return value;
141      }
142    }
143    return null;
144  }
145
146  private _getChoice(count: number, path: string, message: any): any {
147    const pluralChoice = i18nPluralRules.select(count);
148    if (!pluralChoice) {
149      Log.debug('PluralChoice is null.');
150      return path;
151    }
152    return getValue(pluralChoice, message);
153  }
154
155  private _translate(path: string, value: any, params: any): any {
156    if (isNull(value)) {
157      return path;
158    }
159    if (Object.prototype.toString.call(params) === '[object Array]') {
160      value = value.replace(/\{(\d+)\}/g, (_, index) => {
161        if (index > params.length - 1 || index < 0) {
162          return '';
163        }
164        return params[index];
165      });
166    } else if (Object.prototype.toString.call(params) === '[object Object]') {
167      value = value.replace(/\{(\w+)\}/g, (_, name) => {
168        if (name in params) {
169          return params[name];
170        }
171        return '';
172      });
173    } else if (Object.prototype.toString.call(params) === '[object Number]') {
174      value = value.replace(/\{count\}/g, params.toLocaleString(this.locale.replace('_', '-')));
175    } else {
176      return value;
177    }
178    return value;
179  }
180}
181
182/**
183 * Init the i18n object.
184 */
185export default {
186  create: (id: number): I18nInterface | null => {
187    instances[id] = [];
188    if (typeof global.I18n === 'function') {
189      return {};
190    }
191    const i18nObject = {
192      I18n: class extends I18n {
193        constructor(options) {
194          super(options);
195          instances[id].push(this);
196        }
197      }
198    };
199    return {
200      instance: i18nObject
201    };
202  },
203  destroy: (id: number): void => {
204    delete instances[id];
205  }
206};
207